├── .github └── workflows │ └── dart.yml ├── .gitignore ├── .gradle ├── 6.1.1 │ ├── executionHistory │ │ └── executionHistory.lock │ ├── fileChanges │ │ └── last-build.bin │ ├── fileHashes │ │ └── fileHashes.lock │ └── gc.properties ├── buildOutputCleanup │ ├── buildOutputCleanup.lock │ └── cache.properties ├── checksums │ └── checksums.lock └── vcs-1 │ └── gc.properties ├── .metadata ├── .vscode └── launch.json ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── .project ├── .settings │ └── org.eclipse.buildship.core.prefs ├── app │ ├── build.gradle │ ├── google-services.json │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── dev │ │ └── res │ │ │ ├── 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 │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ ├── developine │ │ │ │ └── developine_app │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── tutorials │ │ │ │ └── demo_code │ │ │ │ └── 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 │ │ ├── prod │ │ └── res │ │ │ ├── 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 │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── ios ├── .gitignore ├── Flutter │ ├── .last_build_id │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── 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 ├── l10n.yaml ├── lib ├── app.dart ├── app_parent_view.dart ├── config │ ├── env_config.dart │ ├── flavors.dart │ └── setup_config.dart ├── core │ ├── bloc │ │ ├── base_cubit.dart │ │ ├── bloc_observer.dart │ │ ├── network_cubit.dart │ │ └── network_state.dart │ ├── const │ │ ├── events_constants.dart │ │ ├── exception_constants.dart │ │ ├── network_constants.dart │ │ └── route_constants.dart │ ├── db │ │ ├── app_database.dart │ │ └── app_database.g.dart │ ├── di │ │ ├── cache_container.dart │ │ ├── domain_container.dart │ │ ├── injection_container.dart │ │ ├── presentation_container.dart │ │ └── remote_container.dart │ ├── error │ │ ├── exception.dart │ │ └── failures.dart │ ├── firebase │ │ ├── firebase_analytics_handler.dart │ │ └── firebase_notification_handler.dart │ ├── layout │ │ ├── colored_safearea.dart │ │ └── image_placeholder.dart │ ├── logger │ │ ├── abstract_logger.dart │ │ └── firebase_logger.dart │ ├── model │ │ └── categories.dart │ ├── network │ │ ├── network_client.dart │ │ ├── network_info.dart │ │ └── pretty_dio_logger.dart │ ├── routing │ │ └── routes.dart │ └── util │ │ ├── constant.dart │ │ ├── location_handler.dart │ │ ├── string_apis.dart │ │ ├── theme.dart │ │ ├── theme_controller.dart │ │ ├── utils.dart │ │ └── validation.dart ├── features │ ├── cart │ │ ├── data │ │ │ ├── local │ │ │ │ └── data_sources │ │ │ │ │ └── cart_local_datasource.dart │ │ │ ├── remote │ │ │ │ └── data_sources │ │ │ │ │ └── cart_remote_datasource.dart │ │ │ └── repositories │ │ │ │ └── cart_repo_impl.dart │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── cart_repository.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── cart_bloc.dart │ │ │ ├── cart_event.dart │ │ │ └── cart_state.dart │ │ │ └── pages │ │ │ └── cart_page.dart │ ├── categories │ │ ├── data │ │ │ ├── data_sources │ │ │ │ └── categories_remote_datasource.dart │ │ │ ├── models │ │ │ │ └── categories_ model.dart │ │ │ └── repositories │ │ │ │ └── categories_repo_impl.dart │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── categories_repo.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── categories_bloc.dart │ │ │ ├── categories_event.dart │ │ │ └── categories_state.dart │ │ │ └── pages │ │ │ └── categories_page.dart │ ├── checkout │ │ ├── data │ │ │ ├── data_sources │ │ │ │ └── checkout_remote_datasource.dart │ │ │ ├── models │ │ │ │ └── checkout_model.dart │ │ │ └── repositories │ │ │ │ └── checkout_repo_impl.dart │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── checkout_repo.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── checkout_bloc.dart │ │ │ ├── checkout_event.dart │ │ │ └── checkout_state.dart │ │ │ └── pages │ │ │ └── checkout_page.dart │ ├── detail │ │ ├── data │ │ │ ├── data_sources │ │ │ │ └── detail_remote_datasource.dart │ │ │ └── repositories │ │ │ │ └── detail_repo_impl.dart │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── detail_repository.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── detail_bloc.dart │ │ │ ├── detail_event.dart │ │ │ └── detail_state.dart │ │ │ └── pages │ │ │ └── detail_page.dart │ ├── faqs │ │ └── faqs_page.dart │ ├── history │ │ ├── data │ │ │ └── repositories │ │ │ │ └── history_repo_impl.dart │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── history_repository.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── history_bloc.dart │ │ │ ├── history_event.dart │ │ │ └── history_state.dart │ │ │ └── pages │ │ │ └── history_page.dart │ ├── home │ │ ├── data │ │ │ ├── data_sources │ │ │ │ └── home_remote_datasource.dart │ │ │ ├── models │ │ │ │ └── home_model.dart │ │ │ └── repositories │ │ │ │ └── home_repo_impl.dart │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── home_repo.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── home_bloc.dart │ │ │ ├── home_event.dart │ │ │ └── home_state.dart │ │ │ ├── pages │ │ │ └── home_page.dart │ │ │ └── widgets │ │ │ ├── header_menu_widget.dart │ │ │ └── search_field_widget.dart │ ├── listing │ │ ├── data │ │ │ ├── data_sources │ │ │ │ └── user_list_local_datasource.dart │ │ │ ├── models │ │ │ │ └── user_model.dart │ │ │ └── repositories │ │ │ │ └── user_list_repository_impl.dart │ │ ├── domain │ │ │ ├── entities │ │ │ │ └── user.dart │ │ │ └── repositories │ │ │ │ └── user_list_repository.dart │ │ └── presentation │ │ │ ├── cubit │ │ │ ├── listing_cubit.dart │ │ │ └── listing_state.dart │ │ │ ├── pages │ │ │ └── listing_page.dart │ │ │ └── widgets │ │ │ ├── customer_card.dart │ │ │ ├── customer_card_item.dart │ │ │ ├── customer_list.dart │ │ │ └── search_field.dart │ ├── location │ │ ├── data │ │ │ ├── data_sources │ │ │ │ └── location_remote_datasource.dart │ │ │ ├── models │ │ │ │ └── location_model.dart │ │ │ └── repositories │ │ │ │ └── location_repo_impl.dart │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── location_repo.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── location_bloc.dart │ │ │ ├── location_event.dart │ │ │ └── location_state.dart │ │ │ └── pages │ │ │ └── deliverylocation_page.dart │ ├── login │ │ ├── data │ │ │ ├── data_sources │ │ │ │ ├── login_local_datasource.dart │ │ │ │ └── login_remote_datasource.dart │ │ │ ├── models │ │ │ │ └── login_response_model.dart │ │ │ └── repositories │ │ │ │ └── login_repository_impl.dart │ │ ├── domain │ │ │ ├── entities │ │ │ │ └── login_response.dart │ │ │ └── repositories │ │ │ │ └── login_repository.dart │ │ └── presentation │ │ │ ├── cubit │ │ │ ├── login_cubit.dart │ │ │ └── login_state.dart │ │ │ ├── pages │ │ │ └── login_page.dart │ │ │ └── widgets │ │ │ ├── input_field.dart │ │ │ └── login_button.dart │ ├── notifiations │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── notifications_repo.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── notifications_bloc.dart │ │ │ ├── notifications_event.dart │ │ │ └── notifications_state.dart │ │ │ └── pages │ │ │ └── notifications_page.dart │ ├── password │ │ ├── data │ │ │ ├── data_sources │ │ │ │ └── password_remote_datasource.dart │ │ │ ├── models │ │ │ │ └── password_model.dart │ │ │ └── repositories │ │ │ │ └── password_repo_impl.dart │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── password_repo.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── password_bloc.dart │ │ │ ├── password_event.dart │ │ │ └── password_state.dart │ │ │ └── pages │ │ │ ├── changepassword_page.dart │ │ │ └── forgotpassword_page.dart │ ├── payment │ │ └── presentation │ │ │ └── manager │ │ │ ├── payment_bloc.dart │ │ │ ├── payment_event.dart │ │ │ └── payment_state.dart │ ├── profile │ │ ├── data │ │ │ ├── data_sources │ │ │ │ └── profile_remote_datasource.dart │ │ │ ├── models │ │ │ │ └── profile_model.dart │ │ │ └── repositories │ │ │ │ └── profile_repo_impl.dart │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── profile_repo.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── profile_bloc.dart │ │ │ ├── profile_event.dart │ │ │ └── profile_state.dart │ │ │ └── pages │ │ │ └── profile_page.dart │ ├── search │ │ ├── data │ │ │ ├── data_sources │ │ │ │ └── search_remote_datasource.dart │ │ │ ├── models │ │ │ │ └── search_model.dart │ │ │ └── repositories │ │ │ │ └── search_repo_impl.dart │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── search_repo.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── search_bloc.dart │ │ │ ├── search_event.dart │ │ │ └── search_state.dart │ │ │ └── pages │ │ │ └── search_page.dart │ ├── signup │ │ ├── data │ │ │ ├── data_sources │ │ │ │ └── signup_remote_datasource.dart │ │ │ ├── models │ │ │ │ └── signup_model.dart │ │ │ └── repositories │ │ │ │ └── signup_repo_impl.dart │ │ ├── domain │ │ │ └── repositories │ │ │ │ └── signup_repo.dart │ │ └── presentation │ │ │ ├── manager │ │ │ ├── signup_bloc.dart │ │ │ ├── signup_event.dart │ │ │ └── signup_state.dart │ │ │ └── pages │ │ │ └── signup_page.dart │ ├── splash │ │ └── splash_page.dart │ └── support │ │ ├── data │ │ ├── data_sources │ │ │ └── support_remote_datasource.dart │ │ ├── models │ │ │ └── support_model.dart │ │ └── repositories │ │ │ └── support_repo_impl.dart │ │ ├── domain │ │ └── repositories │ │ │ └── support_repo.dart │ │ └── presentation │ │ ├── manager │ │ ├── support_bloc.dart │ │ ├── support_event.dart │ │ └── support_state.dart │ │ └── pages │ │ ├── feeback_page.dart │ │ └── support_page.dart ├── generated_plugin_registrant.dart ├── l10n │ ├── app_ar.arb │ └── app_en.arb ├── main_dev.dart └── main_prod.dart ├── local.properties ├── pubspec.yaml ├── test ├── features │ ├── listing │ │ ├── data │ │ │ └── repositories │ │ │ │ └── user_list_repository_impl_test.dart │ │ ├── domain │ │ │ └── usecases │ │ │ │ └── get_user_list_test.dart │ │ └── presentation │ │ │ └── bloc │ │ │ └── listing_bloc_test.dart │ └── login │ │ └── presentation │ │ └── bloc │ │ └── login_bloc_test.dart └── widget_test.dart └── web ├── favicon.png ├── icons ├── Icon-192.png └── Icon-512.png ├── index.html └── manifest.json /.github/workflows/dart.yml: -------------------------------------------------------------------------------- 1 | name: Dart 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | # Note that this workflow uses the latest stable version of the Dart SDK. 14 | # Docker images for other release channels - like dev and beta - are also 15 | # available. See https://hub.docker.com/r/google/dart/ for the available 16 | # images. 17 | container: 18 | image: google/dart:latest 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | 23 | - name: Print Dart SDK version 24 | run: dart --version 25 | 26 | - name: Install dependencies 27 | run: dart pub get 28 | 29 | # Uncomment this step to verify the use of 'dart format' on each commit. 30 | # - name: Verify formatting 31 | # run: dart format --output=none --set-exit-if-changed . 32 | 33 | # Consider passing '--fatal-infos' for slightly stricter analysis. 34 | - name: Analyze project source 35 | run: dart analyze 36 | 37 | # Your project will need to have tests in test/ and a dependency on 38 | # package:test for this step to succeed. Note that Flutter projects will 39 | # want to change this to 'flutter test'. 40 | - name: Run tests 41 | run: dart test 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.lock 5 | *.pyc 6 | *.swp 7 | .DS_Store 8 | .atom/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # Visual Studio Code related 20 | .classpath 21 | .project 22 | .settings/ 23 | .vscode/ 24 | 25 | # The .vscode folder contains launch configuration and tasks you configure in 26 | # VS Code which you may wish to be included in version control, so this line 27 | # is commented out by default. 28 | #.vscode/ 29 | 30 | # Flutter/Dart/Pub related 31 | **/doc/api/ 32 | **/ios/Flutter/.last_build_id 33 | .dart_tool/ 34 | .flutter-plugins 35 | .flutter-plugins-dependencies 36 | .packages 37 | .pub-cache/ 38 | /bin/internal/bootstrap.bat 39 | /bin/internal/bootstrap.sh 40 | /bin/mingit/ 41 | /dev/benchmarks/mega_gallery/ 42 | /dev/bots/.recipe_deps 43 | /dev/bots/android_tools/ 44 | /dev/devicelab/ABresults*.json 45 | /dev/docs/doc/ 46 | /dev/docs/flutter.docs.zip 47 | /dev/docs/lib/ 48 | /dev/docs/pubspec.yaml 49 | .pub/ 50 | /build/ 51 | flutter_*.png 52 | linked_*.ds 53 | unlinked.ds 54 | unlinked_spec.ds 55 | .fvm/ 56 | 57 | # Web related 58 | lib/generated_plugin_registrant.dart 59 | 60 | # Submodules 61 | !pubspec.lock 62 | pubspec.lock 63 | packages/**/pubspec.lock 64 | 65 | # Symbolication related 66 | app.*.symbols 67 | 68 | # Obfuscation related 69 | app.*.map.json 70 | 71 | # Android Studio will place build artifacts here 72 | /android/app/debug 73 | /android/app/profile 74 | /android/app/release 75 | 76 | # Android related 77 | **/android/**/gradle-wrapper.jar 78 | **/android/.gradle 79 | **/android/captures/ 80 | **/android/gradlew 81 | **/android/gradlew.bat 82 | **/android/local.properties 83 | **/android/**/GeneratedPluginRegistrant.java 84 | 85 | # iOS/XCode related 86 | **/ios/**/*.mode1v3 87 | **/ios/**/*.mode2v3 88 | **/ios/**/*.moved-aside 89 | **/ios/**/*.pbxuser 90 | **/ios/**/*.perspectivev3 91 | **/ios/**/*sync/ 92 | **/ios/**/.sconsign.dblite 93 | **/ios/**/.tags* 94 | **/ios/**/.vagrant/ 95 | **/ios/**/DerivedData/ 96 | **/ios/**/Icon? 97 | **/ios/**/Pods/ 98 | **/ios/**/.symlinks/ 99 | **/ios/**/profile 100 | **/ios/**/xcuserdata 101 | **/ios/.generated/ 102 | **/ios/Flutter/App.framework 103 | **/ios/Flutter/Flutter.framework 104 | **/ios/Flutter/Generated.xcconfig 105 | **/ios/Flutter/app.flx 106 | **/ios/Flutter/app.zip 107 | **/ios/Flutter/flutter_assets/ 108 | **/ios/ServiceDefinitions.json 109 | **/ios/Runner/GeneratedPluginRegistrant.* 110 | 111 | # Exceptions to above rules. 112 | !**/ios/**/default.mode1v3 113 | !**/ios/**/default.mode2v3 114 | !**/ios/**/default.pbxuser 115 | !**/ios/**/default.perspectivev3 116 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 117 | 118 | -------------------------------------------------------------------------------- /.gradle/6.1.1/executionHistory/executionHistory.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/.gradle/6.1.1/executionHistory/executionHistory.lock -------------------------------------------------------------------------------- /.gradle/6.1.1/fileChanges/last-build.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gradle/6.1.1/fileHashes/fileHashes.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/.gradle/6.1.1/fileHashes/fileHashes.lock -------------------------------------------------------------------------------- /.gradle/6.1.1/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/.gradle/6.1.1/gc.properties -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/buildOutputCleanup.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/.gradle/buildOutputCleanup/buildOutputCleanup.lock -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/cache.properties: -------------------------------------------------------------------------------- 1 | #Wed Jan 20 16:39:47 GST 2021 2 | gradle.version=6.1.1 3 | -------------------------------------------------------------------------------- /.gradle/checksums/checksums.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/.gradle/checksums/checksums.lock -------------------------------------------------------------------------------- /.gradle/vcs-1/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/.gradle/vcs-1/gc.properties -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 9f5ff2306bb3e30b2b98eee79cd231b1336f41f4 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Flutter", 9 | "request": "launch", 10 | "type": "dart" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Demo App 2 | 3 | A new Flutter application. 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://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | 18 | ## Libraries/Frameworks and Architecture 19 | 20 | - Clean Code 21 | - Bloc for Widget state management 22 | - Dio for Networking 23 | - Flutter Localization 24 | - Equatable to facilitate == and hashCode overrides 25 | - DartZ for functional programming 26 | - Get_it for service locator 27 | - Manage theme from single source 28 | 29 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | analyzer: 28 | exclude: 29 | - "**/*.g.dart" 30 | 31 | # Additional information about this file can be found at 32 | # https://dart.dev/guides/language/analysis-options 33 | -------------------------------------------------------------------------------- /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/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | arguments= 2 | auto.sync=false 3 | build.scans.enabled=false 4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 5 | connection.project.dir= 6 | eclipse.preferences.version=1 7 | gradle.user.home= 8 | java.home=/Library/Java/JavaVirtualMachines/openjdk-12.0.2.jdk/Contents/Home 9 | jvm.arguments= 10 | offline.mode=false 11 | override.workspace.settings=true 12 | show.console.view=true 13 | show.executions.view=true 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 | 30 | // ----- BEGIN flavorDimensions (autogenerated by flutter_flavorizr) ----- 31 | flavorDimensions "flavor-type" 32 | 33 | productFlavors { 34 | dev { 35 | dimension "flavor-type" 36 | applicationId "com.developine.developine_app" 37 | resValue "string", "app_name", "developine Dev" 38 | } 39 | prod { 40 | dimension "flavor-type" 41 | applicationId "com.developine.developine_app" 42 | resValue "string", "app_name", "developine " 43 | } 44 | } 45 | 46 | // ----- END flavorDimensions (autogenerated by flutter_flavorizr) ----- 47 | compileSdkVersion flutter.compileSdkVersion 48 | 49 | compileOptions { 50 | sourceCompatibility JavaVersion.VERSION_1_8 51 | targetCompatibility JavaVersion.VERSION_1_8 52 | } 53 | 54 | kotlinOptions { 55 | jvmTarget = '1.8' 56 | } 57 | 58 | sourceSets { 59 | main.java.srcDirs += 'src/main/kotlin' 60 | } 61 | 62 | defaultConfig { 63 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 64 | applicationId "com.developine.developine_app" 65 | minSdkVersion 21 66 | targetSdkVersion flutter.targetSdkVersion 67 | versionCode flutterVersionCode.toInteger() 68 | versionName flutterVersionName 69 | multiDexEnabled true 70 | } 71 | 72 | buildTypes { 73 | debug { 74 | signingConfig signingConfigs.debug 75 | debuggable true 76 | } 77 | release { 78 | shrinkResources false 79 | minifyEnabled false 80 | signingConfig signingConfigs.debug 81 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 82 | } 83 | } 84 | } 85 | 86 | flutter { 87 | source '../..' 88 | } 89 | 90 | dependencies { 91 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 92 | } 93 | 94 | apply plugin: 'com.google.gms.google-services' 95 | apply plugin: 'com.google.firebase.crashlytics' -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "1010263203879", 4 | "project_id": "developine-66453", 5 | "storage_bucket": "developine-66453.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:1010263203879:android:730eb76ca616835edf2e02", 11 | "android_client_info": { 12 | "package_name": "com.developine.developine_app" 13 | } 14 | }, 15 | "oauth_client": [ 16 | { 17 | "client_id": "1010263203879-le7f29t61orve80bv1qqsa2bs9o6qae7.apps.googleusercontent.com", 18 | "client_type": 3 19 | } 20 | ], 21 | "api_key": [ 22 | { 23 | "current_key": "AIzaSyCpYR1cDMYi7j7_px6famqqMA90lclUdnU" 24 | } 25 | ], 26 | "services": { 27 | "appinvite_service": { 28 | "other_platform_oauth_client": [ 29 | { 30 | "client_id": "1010263203879-le7f29t61orve80bv1qqsa2bs9o6qae7.apps.googleusercontent.com", 31 | "client_type": 3 32 | } 33 | ] 34 | } 35 | } 36 | } 37 | ], 38 | "configuration_version": "1" 39 | } -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/dev/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/dev/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/dev/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/dev/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 16 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/developine/developine_app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.developine.developine_app 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/tutorials/demo_code/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.tutorials.demo_code 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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/prod/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/prod/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/prod/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/prod/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/prod/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/prod/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/prod/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/prod/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | classpath 'com.google.gms:google-services:4.3.10' 12 | classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | google() 19 | mavenCentral() 20 | } 21 | } 22 | 23 | rootProject.buildDir = '../build' 24 | subprojects { 25 | project.buildDir = "${rootProject.buildDir}/${project.name}" 26 | } 27 | subprojects { 28 | project.evaluationDependsOn(':app') 29 | } 30 | 31 | task clean(type: Delete) { 32 | delete rootProject.buildDir 33 | } 34 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | #profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /ios/Flutter/.last_build_id: -------------------------------------------------------------------------------- 1 | 22c4cfb87a2df2e663952edf975e3a07 -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def parse_KV_file(file, separator='=') 14 | file_abs_path = File.expand_path(file) 15 | if !File.exists? file_abs_path 16 | return []; 17 | end 18 | generated_key_values = {} 19 | skip_line_start_symbols = ["#", "/"] 20 | File.foreach(file_abs_path) do |line| 21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 22 | plugin = line.split(pattern=separator) 23 | if plugin.length == 2 24 | podname = plugin[0].strip() 25 | path = plugin[1].strip() 26 | podpath = File.expand_path("#{path}", file_abs_path) 27 | generated_key_values[podname] = podpath 28 | else 29 | puts "Invalid plugin specification: #{line}" 30 | end 31 | end 32 | generated_key_values 33 | end 34 | 35 | target 'Runner' do 36 | use_frameworks! 37 | use_modular_headers! 38 | 39 | # Flutter Pod 40 | 41 | copied_flutter_dir = File.join(__dir__, 'Flutter') 42 | copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') 43 | copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') 44 | unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) 45 | # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. 46 | # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. 47 | # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. 48 | 49 | generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') 50 | unless File.exist?(generated_xcode_build_settings_path) 51 | raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" 52 | end 53 | generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) 54 | cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; 55 | 56 | unless File.exist?(copied_framework_path) 57 | FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) 58 | end 59 | unless File.exist?(copied_podspec_path) 60 | FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) 61 | end 62 | end 63 | 64 | # Keep pod path relative so it can be checked into Podfile.lock. 65 | pod 'Flutter', :path => 'Flutter' 66 | 67 | # Plugin Pods 68 | 69 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 70 | # referring to absolute paths on developers' machines. 71 | system('rm -rf .symlinks') 72 | system('mkdir -p .symlinks/plugins') 73 | plugin_pods = parse_KV_file('../.flutter-plugins') 74 | plugin_pods.each do |name, path| 75 | symlink = File.join('.symlinks', 'plugins', name) 76 | File.symlink(path, symlink) 77 | pod name, :path => File.join(symlink, 'ios') 78 | end 79 | end 80 | 81 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 82 | install! 'cocoapods', :disable_input_output_paths => true 83 | 84 | post_install do |installer| 85 | installer.pods_project.targets.each do |target| 86 | target.build_configurations.each do |config| 87 | config.build_settings['ENABLE_BITCODE'] = 'NO' 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - connectivity (0.0.1): 3 | - Flutter 4 | - Reachability 5 | - connectivity_for_web (0.1.0): 6 | - Flutter 7 | - connectivity_macos (0.0.1): 8 | - Flutter 9 | - Flutter (1.0.0) 10 | - path_provider_linux (0.0.1): 11 | - Flutter 12 | - path_provider_windows (0.0.1): 13 | - Flutter 14 | - Reachability (3.2) 15 | - shared_preferences (0.0.1): 16 | - Flutter 17 | - shared_preferences_linux (0.0.1): 18 | - Flutter 19 | - shared_preferences_macos (0.0.1): 20 | - Flutter 21 | - shared_preferences_web (0.0.1): 22 | - Flutter 23 | - shared_preferences_windows (0.0.1): 24 | - Flutter 25 | 26 | DEPENDENCIES: 27 | - connectivity (from `.symlinks/plugins/connectivity/ios`) 28 | - connectivity_for_web (from `.symlinks/plugins/connectivity_for_web/ios`) 29 | - connectivity_macos (from `.symlinks/plugins/connectivity_macos/ios`) 30 | - Flutter (from `Flutter`) 31 | - path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`) 32 | - path_provider_windows (from `.symlinks/plugins/path_provider_windows/ios`) 33 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) 34 | - shared_preferences_linux (from `.symlinks/plugins/shared_preferences_linux/ios`) 35 | - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`) 36 | - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`) 37 | - shared_preferences_windows (from `.symlinks/plugins/shared_preferences_windows/ios`) 38 | 39 | SPEC REPOS: 40 | trunk: 41 | - Reachability 42 | 43 | EXTERNAL SOURCES: 44 | connectivity: 45 | :path: ".symlinks/plugins/connectivity/ios" 46 | connectivity_for_web: 47 | :path: ".symlinks/plugins/connectivity_for_web/ios" 48 | connectivity_macos: 49 | :path: ".symlinks/plugins/connectivity_macos/ios" 50 | Flutter: 51 | :path: Flutter 52 | path_provider_linux: 53 | :path: ".symlinks/plugins/path_provider_linux/ios" 54 | path_provider_windows: 55 | :path: ".symlinks/plugins/path_provider_windows/ios" 56 | shared_preferences: 57 | :path: ".symlinks/plugins/shared_preferences/ios" 58 | shared_preferences_linux: 59 | :path: ".symlinks/plugins/shared_preferences_linux/ios" 60 | shared_preferences_macos: 61 | :path: ".symlinks/plugins/shared_preferences_macos/ios" 62 | shared_preferences_web: 63 | :path: ".symlinks/plugins/shared_preferences_web/ios" 64 | shared_preferences_windows: 65 | :path: ".symlinks/plugins/shared_preferences_windows/ios" 66 | 67 | SPEC CHECKSUMS: 68 | connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467 69 | connectivity_for_web: 2b8584556930d4bd490d82b836bcf45067ce345b 70 | connectivity_macos: e2e9731b6b22dda39eb1b128f6969d574460e191 71 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 72 | path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 73 | path_provider_windows: a2b81600c677ac1959367280991971cb9a1edb3b 74 | Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 75 | shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d 76 | shared_preferences_linux: afefbfe8d921e207f01ede8b60373d9e3b566b78 77 | shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 78 | shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9 79 | shared_preferences_windows: 36b76d6f54e76ead957e60b49e2f124b4cd3e6ae 80 | 81 | PODFILE CHECKSUM: 1b66dae606f75376c5f2135a8290850eeb09ae83 82 | 83 | COCOAPODS: 1.9.3 84 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/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/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_app 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /l10n.yaml: -------------------------------------------------------------------------------- 1 | arb-dir: lib/l10n 2 | template-arb-file: app_en.arb 3 | output-localization-file: app_localizations.dart -------------------------------------------------------------------------------- /lib/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:developine_app/app_parent_view.dart'; 2 | import 'package:developine_app/core/bloc/network_cubit.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | import 'core/di/injection_container.dart'; 6 | import 'features/login/presentation/cubit/login_cubit.dart'; 7 | 8 | class App extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return MultiBlocProvider( 12 | providers: [ 13 | BlocProvider( 14 | create: (_) => serviceLocator(), 15 | ), 16 | BlocProvider( 17 | create: (_) => serviceLocator(), 18 | ), 19 | ], 20 | child: AppParentView(), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/app_parent_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_analytics/firebase_analytics.dart'; 2 | import 'package:firebase_analytics/observer.dart'; 3 | import 'package:firebase_crashlytics/firebase_crashlytics.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_localizations/flutter_localizations.dart'; 6 | import 'core/const/route_constants.dart'; 7 | import 'core/routing/routes.dart'; 8 | import 'core/util/constant.dart'; 9 | import 'core/util/theme.dart'; 10 | 11 | class AppParentView extends StatefulWidget { 12 | const AppParentView({Key? key}) : super(key: key); 13 | 14 | @override 15 | State createState() { 16 | return _AppParentViewState(); 17 | } 18 | } 19 | 20 | class _AppParentViewState extends State { 21 | // Adding English and Arabic support. 22 | var supportedLocales = [const Locale('en', ''), const Locale('ar', '')]; 23 | static FirebaseAnalytics analytics = FirebaseAnalytics.instance; 24 | static FirebaseAnalyticsObserver observer = 25 | FirebaseAnalyticsObserver(analytics: analytics); 26 | 27 | @override 28 | void initState() { 29 | super.initState(); 30 | _initializeFlutterFire(); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return MaterialApp( 36 | localizationsDelegates: const [ 37 | GlobalMaterialLocalizations.delegate, 38 | GlobalWidgetsLocalizations.delegate, 39 | GlobalCupertinoLocalizations.delegate, 40 | ], 41 | supportedLocales: supportedLocales, 42 | title: 'DEVELOPINE', 43 | navigatorKey: RouteNavigator.navigatorKey, 44 | navigatorObservers: [observer], 45 | onGenerateRoute: RouteNavigator.generateNamedRoute, 46 | routes: RouteNavigator.routesList, 47 | // TODO: implement Route navigation. 48 | onGenerateInitialRoutes: RouteNavigator.defaultGenerateInitialRoutes, 49 | theme: lightTheme, 50 | initialRoute: RoutesList.initialRoute, 51 | debugShowCheckedModeBanner: false, 52 | ); 53 | } 54 | 55 | // Define an async function to 56 | // initialize FlutterFire 57 | Future _initializeFlutterFire() async { 58 | // Wait for Firebase to initialize 59 | if (kTestingCrashlytics) { 60 | // Force enable crashlytics collection enabled if we're testing it. 61 | await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); 62 | } else { 63 | // Else only enable it in non-debug builds. 64 | // You could additionally extend this to allow users to opt-in. 65 | await FirebaseCrashlytics.instance 66 | .setCrashlyticsCollectionEnabled(!kDebugMode); 67 | } 68 | // Pass all uncaught errors to Crashlytics. 69 | Function originalOnError = FlutterError.onError as Function; 70 | FlutterError.onError = (FlutterErrorDetails errorDetails) async { 71 | await FirebaseCrashlytics.instance.recordFlutterError(errorDetails); 72 | // Forward to original handler. 73 | originalOnError(errorDetails); 74 | }; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/config/env_config.dart: -------------------------------------------------------------------------------- 1 | enum EnvType { development, production } 2 | 3 | class GlobalAppConfig { 4 | final String? appName; 5 | final String? flavorName; 6 | final String? apiBaseURL; 7 | 8 | GlobalAppConfig( 9 | {required this.appName, 10 | required this.flavorName, 11 | required this.apiBaseURL}); 12 | 13 | static GlobalAppConfig? _globalAppConfig; 14 | 15 | static GlobalAppConfig? getInstance({appName, flavorName, apiBaseUrl}) { 16 | if (_globalAppConfig == null) { 17 | _globalAppConfig = GlobalAppConfig( 18 | appName: appName, flavorName: flavorName, apiBaseURL: apiBaseUrl); 19 | return _globalAppConfig; 20 | } 21 | return _globalAppConfig; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/config/flavors.dart: -------------------------------------------------------------------------------- 1 | enum Flavor { 2 | dev, 3 | prod, 4 | } 5 | 6 | class F { 7 | static Flavor? appFlavor; 8 | 9 | static String get name => appFlavor?.name ?? ''; 10 | 11 | static String get baseURL { 12 | switch (appFlavor) { 13 | case Flavor.dev: 14 | return 'https://ae-api-dev.developine.com'; 15 | case Flavor.prod: 16 | return 'https://ae-api.developine.com'; 17 | default: 18 | return ''; 19 | } 20 | } 21 | 22 | static String get title { 23 | switch (appFlavor) { 24 | case Flavor.dev: 25 | return 'developine dev'; 26 | case Flavor.prod: 27 | return 'developine '; 28 | default: 29 | return 'title'; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/config/setup_config.dart: -------------------------------------------------------------------------------- 1 | import 'env_config.dart'; 2 | 3 | class SetupConfig { 4 | void startDev() { 5 | GlobalAppConfig.getInstance(appName: '', flavorName: '', apiBaseUrl: ''); 6 | } 7 | 8 | void startProd() { 9 | GlobalAppConfig.getInstance(appName: '', flavorName: '', apiBaseUrl: ''); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/core/bloc/base_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'dart:developer'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | import '../error/exception.dart'; 6 | import 'package:bloc/bloc.dart'; 7 | 8 | abstract class BaseCubit extends BlocBase { 9 | /// {@macro cubit} 10 | BaseCubit(State initialState) : super(initialState); 11 | 12 | String handleException(Exception exception) { 13 | var message = ""; 14 | if (exception is ServerException) { 15 | return handleDioError(exception.dioError); 16 | } else if (exception is NoInternetException) { 17 | message = "No internet connection available"; 18 | } else { 19 | message = "An Exception has occurred"; 20 | } 21 | 22 | log("Cubit response.fold left: " + message); 23 | return message; 24 | } 25 | 26 | handleDioError(DioError dioError) { 27 | String message = ""; 28 | switch (dioError.type) { 29 | case DioErrorType.cancel: 30 | message = "Request was cancelled"; 31 | break; 32 | case DioErrorType.connectTimeout: 33 | message = "Connection timeout"; 34 | break; 35 | case DioErrorType.other: 36 | message = "Connection failed due to internet connection"; 37 | break; 38 | case DioErrorType.receiveTimeout: 39 | message = "Receive timeout in connection"; 40 | break; 41 | case DioErrorType.response: 42 | { 43 | if (dioError.response?.statusCode == 204) { 44 | } else if (dioError.response?.statusCode == 400) { 45 | // BadRequestException 46 | message = "BadRequestException"; 47 | } else if (dioError.response?.statusCode == 401) { 48 | // UnauthorisedException 49 | message = "UnauthorisedException"; 50 | } else if (dioError.response?.statusCode == 403) { 51 | // ForbiddenException 52 | message = "ForbiddenException"; 53 | } else if (dioError.response?.statusCode == 500) { 54 | // ServerException 55 | message = "ServerException"; 56 | } else { 57 | message = 58 | "Received invalid status code: ${dioError.response?.statusCode}"; 59 | } 60 | } 61 | break; 62 | case DioErrorType.sendTimeout: 63 | message = "Receive timeout in send request"; 64 | break; 65 | } 66 | return message; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/core/bloc/bloc_observer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:developer'; 2 | import 'package:bloc/bloc.dart'; 3 | 4 | class CubitObserver extends BlocObserver { 5 | @override 6 | void onChange(BlocBase bloc, Change change) { 7 | log('CubitObserver onChange: (${bloc.runtimeType}, $change)'); 8 | super.onChange(bloc, change); 9 | } 10 | 11 | @override 12 | void onError(BlocBase bloc, Object error, StackTrace stackTrace) { 13 | log('CubitObserver onError: (${bloc.runtimeType}, $error, $stackTrace)'); 14 | super.onError(bloc, error, stackTrace); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/core/bloc/network_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:developer'; 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | import 'package:simple_connection_checker/simple_connection_checker.dart'; 6 | import 'network_state.dart'; 7 | 8 | class NetworkCubit extends Cubit { 9 | StreamSubscription? subscription; 10 | SimpleConnectionChecker simpleConnectionChecker = SimpleConnectionChecker(); 11 | 12 | NetworkCubit() : super(NetworkInitialState()) { 13 | subscription = 14 | simpleConnectionChecker.onConnectionChange.listen((connected) { 15 | log("Network onConnectionChange: $connected"); 16 | connected 17 | ? emit(NetworkConnectedState()) 18 | : emit(NetworkDisConnectedState()); 19 | }); 20 | } 21 | 22 | @override 23 | Future close() { 24 | subscription?.cancel(); 25 | return super.close(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/core/bloc/network_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class NetworkState extends Equatable { 4 | String get message; 5 | } 6 | 7 | class NetworkConnectedState extends NetworkState { 8 | @override 9 | List get props => []; 10 | 11 | @override 12 | String get message => "Internet connected"; 13 | } 14 | 15 | class NetworkInitialState extends NetworkState { 16 | @override 17 | List get props => []; 18 | 19 | @override 20 | String get message => "Checking internet connection"; 21 | } 22 | 23 | class NetworkDisConnectedState extends NetworkState { 24 | @override 25 | List get props => []; 26 | 27 | @override 28 | String get message => "Inernet is not connected"; 29 | } 30 | -------------------------------------------------------------------------------- /lib/core/const/events_constants.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/core/const/events_constants.dart -------------------------------------------------------------------------------- /lib/core/const/exception_constants.dart: -------------------------------------------------------------------------------- 1 | class ExceptionConstants { 2 | static String unauthorized = 'UNAUTHORIZED'; 3 | static String badRequest = 'BAD_REQUEST'; 4 | static String forbidden = 'FORBIDDEN'; 5 | static String notFound = 'NOT_FOUND'; 6 | static String internalServerError = 'INTERNAL_SERVER_ERROR'; 7 | static String somethingWentWrong = '"something went wrong"'; 8 | } 9 | -------------------------------------------------------------------------------- /lib/core/const/network_constants.dart: -------------------------------------------------------------------------------- 1 | const String kApiVersion = '/v1'; 2 | const String kApiPrefix = '/api'; 3 | const int kTimeOut = 25; 4 | 5 | /// 6 | /// API ENDPOINTS 7 | /// 8 | const String kloginAPI = ""; 9 | const String klogoutAPI = ""; 10 | const String kproductsAPI = ""; 11 | -------------------------------------------------------------------------------- /lib/core/const/route_constants.dart: -------------------------------------------------------------------------------- 1 | class RoutesList { 2 | // routes 3 | static const String initialRoute = '/'; 4 | static const String loginRoute = 'login'; 5 | static const String splashRoute = 'splash'; 6 | static const String homeRoute = 'home'; 7 | static const String searchRoute = 'search'; 8 | static const String transactionRoute = 'transactions'; 9 | } 10 | -------------------------------------------------------------------------------- /lib/core/db/app_database.dart: -------------------------------------------------------------------------------- 1 | import 'package:drift/drift.dart'; 2 | import 'package:drift/native.dart'; 3 | import 'package:path_provider/path_provider.dart' as paths; 4 | import '../model/categories.dart'; 5 | import 'package:path/path.dart' as p; 6 | import 'dart:io'; 7 | part 'app_database.g.dart'; 8 | 9 | @DriftDatabase(tables: [Categories]) 10 | class AppDatabase extends _$AppDatabase { 11 | AppDatabase(QueryExecutor e) : super(e); 12 | 13 | @override 14 | int get schemaVersion => 3; 15 | 16 | /* 17 | * All DB Queries 18 | * */ 19 | Future> get allCategories => select(categories).get(); 20 | 21 | Stream> watchAllCategories() => select(categories).watch(); 22 | 23 | Future insertNewCategory(Category category) => 24 | into(categories).insert(category); 25 | 26 | Future deleteCategory(Category category) => 27 | delete(categories).delete(category); 28 | } 29 | 30 | AppDatabase openConnection({bool logStatements = true}) { 31 | if (Platform.isIOS || Platform.isAndroid) { 32 | final executor = LazyDatabase(() async { 33 | final dataDir = await paths.getApplicationDocumentsDirectory(); 34 | final dbFile = File(p.join(dataDir.path, 'dukkantekpos.sqlite')); 35 | return NativeDatabase(dbFile, logStatements: logStatements); 36 | }); 37 | return AppDatabase(executor); 38 | } 39 | return AppDatabase(NativeDatabase.memory(logStatements: logStatements)); 40 | } 41 | -------------------------------------------------------------------------------- /lib/core/db/app_database.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'app_database.dart'; 4 | 5 | // ************************************************************************** 6 | // MoorGenerator 7 | // ************************************************************************** 8 | 9 | // ignore_for_file: unnecessary_brace_in_string_interps, unnecessary_this 10 | class Category extends DataClass implements Insertable { 11 | final int id; 12 | final String description; 13 | Category({required this.id, required this.description}); 14 | factory Category.fromData(Map data, {String? prefix}) { 15 | final effectivePrefix = prefix ?? ''; 16 | return Category( 17 | id: const IntType() 18 | .mapFromDatabaseResponse(data['${effectivePrefix}id'])!, 19 | description: const StringType() 20 | .mapFromDatabaseResponse(data['${effectivePrefix}description'])!, 21 | ); 22 | } 23 | @override 24 | Map toColumns(bool nullToAbsent) { 25 | final map = {}; 26 | map['id'] = Variable(id); 27 | map['description'] = Variable(description); 28 | return map; 29 | } 30 | 31 | CategoriesCompanion toCompanion(bool nullToAbsent) { 32 | return CategoriesCompanion( 33 | id: Value(id), 34 | description: Value(description), 35 | ); 36 | } 37 | 38 | factory Category.fromJson(Map json, 39 | {ValueSerializer? serializer}) { 40 | serializer ??= driftRuntimeOptions.defaultSerializer; 41 | return Category( 42 | id: serializer.fromJson(json['id']), 43 | description: serializer.fromJson(json['description']), 44 | ); 45 | } 46 | @override 47 | Map toJson({ValueSerializer? serializer}) { 48 | serializer ??= driftRuntimeOptions.defaultSerializer; 49 | return { 50 | 'id': serializer.toJson(id), 51 | 'description': serializer.toJson(description), 52 | }; 53 | } 54 | 55 | Category copyWith({int? id, String? description}) => Category( 56 | id: id ?? this.id, 57 | description: description ?? this.description, 58 | ); 59 | @override 60 | String toString() { 61 | return (StringBuffer('Category(') 62 | ..write('id: $id, ') 63 | ..write('description: $description') 64 | ..write(')')) 65 | .toString(); 66 | } 67 | 68 | @override 69 | int get hashCode => Object.hash(id, description); 70 | @override 71 | bool operator ==(Object other) => 72 | identical(this, other) || 73 | (other is Category && 74 | other.id == this.id && 75 | other.description == this.description); 76 | } 77 | 78 | class CategoriesCompanion extends UpdateCompanion { 79 | final Value id; 80 | final Value description; 81 | const CategoriesCompanion({ 82 | this.id = const Value.absent(), 83 | this.description = const Value.absent(), 84 | }); 85 | CategoriesCompanion.insert({ 86 | this.id = const Value.absent(), 87 | required String description, 88 | }) : description = Value(description); 89 | static Insertable custom({ 90 | Expression? id, 91 | Expression? description, 92 | }) { 93 | return RawValuesInsertable({ 94 | if (id != null) 'id': id, 95 | if (description != null) 'description': description, 96 | }); 97 | } 98 | 99 | CategoriesCompanion copyWith({Value? id, Value? description}) { 100 | return CategoriesCompanion( 101 | id: id ?? this.id, 102 | description: description ?? this.description, 103 | ); 104 | } 105 | 106 | @override 107 | Map toColumns(bool nullToAbsent) { 108 | final map = {}; 109 | if (id.present) { 110 | map['id'] = Variable(id.value); 111 | } 112 | if (description.present) { 113 | map['description'] = Variable(description.value); 114 | } 115 | return map; 116 | } 117 | 118 | @override 119 | String toString() { 120 | return (StringBuffer('CategoriesCompanion(') 121 | ..write('id: $id, ') 122 | ..write('description: $description') 123 | ..write(')')) 124 | .toString(); 125 | } 126 | } 127 | 128 | class $CategoriesTable extends Categories 129 | with TableInfo<$CategoriesTable, Category> { 130 | @override 131 | final GeneratedDatabase attachedDatabase; 132 | final String? _alias; 133 | $CategoriesTable(this.attachedDatabase, [this._alias]); 134 | final VerificationMeta _idMeta = const VerificationMeta('id'); 135 | @override 136 | late final GeneratedColumn id = GeneratedColumn( 137 | 'id', aliasedName, false, 138 | type: const IntType(), 139 | requiredDuringInsert: false, 140 | defaultConstraints: 'PRIMARY KEY AUTOINCREMENT'); 141 | final VerificationMeta _descriptionMeta = 142 | const VerificationMeta('description'); 143 | @override 144 | late final GeneratedColumn description = GeneratedColumn( 145 | 'description', aliasedName, false, 146 | type: const StringType(), requiredDuringInsert: true); 147 | @override 148 | List get $columns => [id, description]; 149 | @override 150 | String get aliasedName => _alias ?? 'categories'; 151 | @override 152 | String get actualTableName => 'categories'; 153 | @override 154 | VerificationContext validateIntegrity(Insertable instance, 155 | {bool isInserting = false}) { 156 | final context = VerificationContext(); 157 | final data = instance.toColumns(true); 158 | if (data.containsKey('id')) { 159 | context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); 160 | } 161 | if (data.containsKey('description')) { 162 | context.handle( 163 | _descriptionMeta, 164 | description.isAcceptableOrUnknown( 165 | data['description']!, _descriptionMeta)); 166 | } else if (isInserting) { 167 | context.missing(_descriptionMeta); 168 | } 169 | return context; 170 | } 171 | 172 | @override 173 | Set get $primaryKey => {id}; 174 | @override 175 | Category map(Map data, {String? tablePrefix}) { 176 | return Category.fromData(data, 177 | prefix: tablePrefix != null ? '$tablePrefix.' : null); 178 | } 179 | 180 | @override 181 | $CategoriesTable createAlias(String alias) { 182 | return $CategoriesTable(attachedDatabase, alias); 183 | } 184 | } 185 | 186 | abstract class _$AppDatabase extends GeneratedDatabase { 187 | _$AppDatabase(QueryExecutor e) : super(SqlTypeSystem.defaultInstance, e); 188 | late final $CategoriesTable categories = $CategoriesTable(this); 189 | @override 190 | Iterable get allTables => allSchemaEntities.whereType(); 191 | @override 192 | List get allSchemaEntities => [categories]; 193 | } 194 | -------------------------------------------------------------------------------- /lib/core/di/cache_container.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/core/di/domain_container.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/core/di/injection_container.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:developine_app/core/bloc/network_cubit.dart'; 3 | import 'package:dio/adapter.dart'; 4 | import 'package:dio/dio.dart'; 5 | import 'package:get_it/get_it.dart'; 6 | import 'package:shared_preferences/shared_preferences.dart'; 7 | import 'package:simple_connection_checker/simple_connection_checker.dart'; 8 | import '../../config/env_config.dart'; 9 | import '../../features/login/data/data_sources/login_local_datasource.dart'; 10 | import '../../features/login/data/data_sources/login_remote_datasource.dart'; 11 | import '../../features/login/data/repositories/login_repository_impl.dart'; 12 | import '../../features/login/domain/repositories/login_repository.dart'; 13 | import '../../features/login/presentation/cubit/login_cubit.dart'; 14 | import '../db/app_database.dart'; 15 | import '../logger/firebase_logger.dart'; 16 | import '../network/network_client.dart'; 17 | import '../network/network_info.dart'; 18 | import '../network/pretty_dio_logger.dart'; 19 | 20 | final serviceLocator = GetIt.I; 21 | 22 | Future initDI() async { 23 | // TODO: SEPARATE REMOTE, CACHE, DOMAIN, DATA DEPENDENCIES 24 | 25 | Dio _dio = Dio(); 26 | BaseOptions baseOptions = BaseOptions( 27 | receiveTimeout: 5000, 28 | connectTimeout: 5000, 29 | headers: {"Content-Type": "application/json"}, 30 | baseUrl: GlobalAppConfig.getInstance()?.apiBaseURL ?? "", 31 | maxRedirects: 2); 32 | _dio.options = baseOptions; 33 | 34 | (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = 35 | (client) { 36 | client.badCertificateCallback = 37 | (X509Certificate cert, String host, int port) => true; 38 | return client; 39 | }; 40 | 41 | _dio.interceptors.clear(); 42 | 43 | _dio.interceptors.add(PrettyDioLogger( 44 | requestBody: true, 45 | error: true, 46 | request: true, 47 | compact: true, 48 | maxWidth: 90, 49 | requestHeader: true, 50 | responseBody: true, 51 | responseHeader: false)); 52 | 53 | _dio.interceptors.add(InterceptorsWrapper(onError: (DioError error, handler) { 54 | return handler.next(error); 55 | }, onRequest: (RequestOptions requestOptions, handler) async { 56 | return handler.next(requestOptions); 57 | }, onResponse: (response, handler) async { 58 | return handler.next(response); 59 | })); 60 | 61 | serviceLocator.registerLazySingleton(() => _dio); 62 | 63 | // Firebase logger 64 | serviceLocator.registerLazySingleton(() => FirebaseLogger()); 65 | 66 | // Database initialize. 67 | serviceLocator.registerSingleton(() => openConnection()); 68 | 69 | // Network Client. 70 | serviceLocator 71 | .registerLazySingleton(() => NetworkClient(dio: serviceLocator())); 72 | 73 | // Local Cache/ Shared Preferences 74 | final sharedPreferences = await SharedPreferences.getInstance(); 75 | final connectionChecker = SimpleConnectionChecker() 76 | ..setLookUpAddress('pub.dev'); 77 | 78 | serviceLocator 79 | .registerLazySingleton(() => sharedPreferences); 80 | 81 | serviceLocator 82 | .registerLazySingleton(() => connectionChecker); 83 | 84 | serviceLocator.registerLazySingleton(() => NetworkInfoImpl()); 85 | 86 | // DATA SOURCES 87 | serviceLocator.registerLazySingleton( 88 | () => LoginRemoteDataSourceImpl(networkClient: serviceLocator())); 89 | 90 | serviceLocator.registerLazySingleton( 91 | () => LoginLocalDataSourceImpl(sharedPreferences: serviceLocator())); 92 | 93 | // REPOSITORIES 94 | serviceLocator.registerLazySingleton(() => 95 | LoginRepositoryImpl( 96 | networkInfoImpl: serviceLocator(), 97 | loginLocalDataSourceImpl: serviceLocator(), 98 | loginRemoteDataSourceImpl: serviceLocator())); 99 | 100 | // // BLOC 101 | serviceLocator.registerFactory( 102 | () => LoginCubit(loginRepository: serviceLocator())); 103 | 104 | serviceLocator.registerFactory(() => NetworkCubit()); 105 | 106 | // USE CASES 107 | 108 | // DATA SOURCES 109 | 110 | // REPOSITORIES 111 | 112 | // USE CASES 113 | 114 | // BLOC 115 | } 116 | -------------------------------------------------------------------------------- /lib/core/di/presentation_container.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/core/di/remote_container.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/core/error/exception.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | 3 | enum ErrorType { 4 | nointernet, 5 | badrequest, 6 | unauthorised, 7 | forbidden, 8 | success, 9 | other 10 | } 11 | 12 | class ServerException implements Exception { 13 | late DioError dioError; 14 | late String? message; 15 | late ErrorType? errorType; 16 | 17 | ServerException({required this.dioError, this.message, this.errorType}); 18 | 19 | ServerException.withException({required DioError dioError}) {} 20 | } 21 | 22 | class NoInternetException implements Exception { 23 | final String message; 24 | 25 | NoInternetException({required this.message}); 26 | } 27 | 28 | class CacheException implements Exception {} 29 | -------------------------------------------------------------------------------- /lib/core/error/failures.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class Failure extends Equatable { 4 | final String message; 5 | 6 | const Failure(this.message); 7 | 8 | @override 9 | List get props => [message]; 10 | } 11 | 12 | class ServerFailure extends Failure { 13 | const ServerFailure(message) : super(message); 14 | } 15 | 16 | class CacheFailure extends Failure { 17 | const CacheFailure(message) : super(message); 18 | } 19 | 20 | enum LocationFailureReason { denied, disabled, unknown } 21 | 22 | class LocationFailure extends Failure { 23 | const LocationFailure(message, LocationFailureReason) 24 | : super( 25 | message, 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /lib/core/firebase/firebase_analytics_handler.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_analytics/firebase_analytics.dart'; 2 | 3 | class FirebaseAnalyticsHandler { 4 | // LOGIN , SIGNUP EVENTS 5 | static const String loginSuccessEvent = "login"; 6 | static const String signupEvent = "sign_up"; 7 | static const String loginFailedEvent = "login_failed_event"; 8 | static String passwordForgotEvent = "password_forgot_event"; 9 | 10 | // A user search for content 11 | static const String searchEvent = "search"; 12 | static const String shareEvent = "share"; 13 | 14 | // A user completes a purchase 15 | static const String purchaseEvent = "purchase"; 16 | static const String purchaseFailedEvent = "purchase_failed"; 17 | static const String ratePurchaseEvent = "rate_purchase"; 18 | static const String repeatPurchaseEvent = "repeat_purchase"; 19 | 20 | // CART EVENTS 21 | static String removeFromCartEvent = "remove_from_cart"; 22 | static String selectItemEvent = "select_item"; 23 | static String addItemToCartEvent = "add_to_cart"; 24 | 25 | // A user begins checkout 26 | static String beginCheckoutEvent = "begin_checkout"; 27 | static String addShippingInfoEvent = "add_shipping_info"; 28 | static String addPaymentInfoEvent = "add_payment_info"; 29 | 30 | // A user add item to wishlist 31 | static String addItemWishlistEvent = "add_to_wishlist"; 32 | 33 | // VIEW EVENTS 34 | static String viewItemListEvent = "view_item_list"; 35 | static String viewCartEvent = "view_cart"; 36 | static String viewCategoriesEvent = "view_categories"; 37 | static String viewAccountEvent = "view_account_page"; 38 | static String viewSettingsEvent = "view_settings_page"; 39 | static String viewItemDetailPageEvent = "view_item_detail_page"; 40 | static String viewPromotionEvent = "view_promotion"; 41 | static String viewOrderHistoryEvent = "view_history"; 42 | static String viewVideoAdEvent = "view_video_ad"; 43 | static String viewPopularRecommendedEvent = 44 | "view_recommended_popular_section"; 45 | 46 | // A user opens support/contact form. 47 | static String viewContactInfoEvent = "view_contact_info"; 48 | 49 | // A user has opened notification from status bar. 50 | static String viewNotificationEvent = "notification_open"; 51 | static String receiveNotificationEvent = "notification_receive"; 52 | 53 | logFirebaseEvent(String eventName, Map params) async { 54 | await FirebaseAnalytics.instance 55 | .logEvent(name: eventName, parameters: params); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/core/firebase/firebase_notification_handler.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:firebase_messaging/firebase_messaging.dart'; 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:firebase_core/firebase_core.dart'; 5 | import 'package:firebase_crashlytics/firebase_crashlytics.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter_local_notifications/flutter_local_notifications.dart'; 8 | 9 | /// Create a [AndroidNotificationChannel] for heads up notifications 10 | const AndroidNotificationChannel channel = AndroidNotificationChannel( 11 | 'high_importance_channel', // id 12 | 'High Importance Notifications', 13 | importance: Importance.high, 14 | ); 15 | 16 | _initNotificationChannel() async { 17 | /// Create an Android Notification Channel. 18 | /// 19 | /// We use this channel in the `AndroidManifest.xml` file to override the 20 | /// default FCM channel to enable heads up notifications. 21 | await flutterLocalNotificationsPlugin 22 | .resolvePlatformSpecificImplementation< 23 | AndroidFlutterLocalNotificationsPlugin>() 24 | ?.createNotificationChannel(channel); 25 | 26 | /// Update the iOS foreground notification presentation options to allow 27 | /// heads up notifications. 28 | await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( 29 | alert: true, 30 | badge: true, 31 | sound: true, 32 | ); 33 | } 34 | 35 | Future? _onSelectNotification(String? payloadNotification) { 36 | if (kDebugMode) { 37 | print("Notification selected."); 38 | } 39 | 40 | WidgetsBinding.instance.addPostFrameCallback((_) { 41 | if (payloadNotification != null && payloadNotification != "") { 42 | if (kDebugMode) { 43 | print(payloadNotification); 44 | } 45 | 46 | // parse notification content like this. 47 | // PushRequest.Message message = 48 | // PushRequest.Message.fromJson(jsonDecode(payloadNotification)); 49 | // 50 | } 51 | }); 52 | return null; 53 | } 54 | 55 | Future initFirebaseApp() async { 56 | await Firebase.initializeApp(); 57 | FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterError; 58 | 59 | // For handling notification when the app is in terminated state 60 | FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) { 61 | if (message != null) { 62 | if (kDebugMode) { 63 | print('FirebaseMessaging getInitialMessage() is called.'); 64 | } 65 | message.data.forEach((dynamicKey, dynamicValue) { 66 | if (dynamicKey == "message" && dynamicValue != null) { 67 | // Parse notification like this. 68 | // PushRequest.Message message = PushRequest.Message.fromJson( 69 | // jsonDecode(dynamicValue.toString())); 70 | // payLoad = jsonEncode(message); 71 | // 72 | } 73 | }); 74 | } 75 | }); 76 | 77 | var initializationSettingsAndroid = 78 | const AndroidInitializationSettings('launch_background'); 79 | var initializationSettingsIOs = const IOSInitializationSettings(); 80 | var initSettings = InitializationSettings( 81 | android: initializationSettingsAndroid, iOS: initializationSettingsIOs); 82 | 83 | flutterLocalNotificationsPlugin.initialize(initSettings, 84 | onSelectNotification: _onSelectNotification); 85 | 86 | _initNotificationChannel(); 87 | 88 | // Set the background messaging handler early on, as a named top-level function 89 | FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); 90 | 91 | FirebaseMessaging.onMessage.listen((RemoteMessage remoteMessage) { 92 | if (kDebugMode) { 93 | print('Got a message whilst in the foreground: ' + 94 | remoteMessage.data.toString()); 95 | } 96 | 97 | remoteMessage.data.forEach((dynamicKey, dynamicValue) { 98 | if (dynamicKey == "message" && dynamicValue != null) { 99 | // Parse notification data like this. 100 | // PushRequest.Message message = PushRequest.Message.fromJson( 101 | // jsonDecode(dynamicValue.toString())); 102 | // 103 | } 104 | }); 105 | 106 | if (remoteMessage.notification != null) { 107 | if (kDebugMode) { 108 | print( 109 | 'Message also contained a notification: ${remoteMessage.notification?.body}'); 110 | } 111 | if (kDebugMode) { 112 | print('Apple notification: ${remoteMessage.notification?.apple}'); 113 | } 114 | } 115 | }); 116 | 117 | FirebaseMessaging.onMessageOpenedApp.listen((remoteMessage) { 118 | if (kDebugMode) { 119 | print('Message clicked!'); 120 | } 121 | remoteMessage.data.forEach((dynamicKey, dynamicValue) { 122 | if (dynamicKey == "message" && dynamicValue != null) { 123 | // Parse notification data like this. 124 | // PushRequest.Message message = PushRequest.Message.fromJson( 125 | // jsonDecode(dynamicValue.toString())); 126 | // } 127 | } 128 | }); 129 | }); 130 | 131 | final NotificationAppLaunchDetails? notificationAppLaunchDetails = 132 | await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails(); 133 | 134 | if (notificationAppLaunchDetails?.didNotificationLaunchApp == true) { 135 | if (notificationAppLaunchDetails?.payload != null) { 136 | // payLoad = notificationAppLaunchDetails.payload; 137 | } 138 | } 139 | } 140 | 141 | Future _firebaseMessagingBackgroundHandler( 142 | RemoteMessage? remoteMessage) async { 143 | if (remoteMessage?.data != null) { 144 | remoteMessage?.data.forEach((dynamicKey, dynamicValue) { 145 | if (dynamicKey == "message") { 146 | // Parse notification like below 147 | // PushRequest.Message message = 148 | // PushRequest.Message.fromJson(jsonDecode(dynamicValue.toString())); 149 | // 150 | // call show notification. 151 | } 152 | }); 153 | } else { 154 | if (kDebugMode) { 155 | print('Notification Message is null.'); 156 | } 157 | } 158 | } 159 | 160 | FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = 161 | FlutterLocalNotificationsPlugin(); 162 | 163 | showNotification() async { 164 | var android = const AndroidNotificationDetails( 165 | 'id', 'notification_app_channel ', 166 | priority: Priority.high, 167 | importance: Importance.max, 168 | setAsGroupSummary: true); 169 | 170 | var iOS = const IOSNotificationDetails(); 171 | var notificationDetail = 172 | NotificationDetails(android: android, iOS: iOS, macOS: null); 173 | await flutterLocalNotificationsPlugin.show( 174 | 123, 'DUKKANTEK', "Notification Title", notificationDetail, 175 | payload: jsonEncode("Notification pojo class")); 176 | } 177 | -------------------------------------------------------------------------------- /lib/core/layout/colored_safearea.dart: -------------------------------------------------------------------------------- 1 | import 'package:developine_app/core/util/theme.dart'; 2 | import 'package:flutter/material.dart'; 3 | import '../../config/flavors.dart'; 4 | 5 | class ColoredSafeArea extends StatelessWidget { 6 | final Widget child; 7 | final Color? color; 8 | final bool? showBanner; 9 | 10 | const ColoredSafeArea( 11 | {Key? key, 12 | required this.child, 13 | this.color = onPrimaryColor, 14 | this.showBanner}) 15 | : super(key: key); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return showBanner ?? false 20 | ? Banner( 21 | message: F.name, 22 | location: BannerLocation.topStart, 23 | child: safeWidget(context), 24 | color: Colors.blue.withOpacity(0.6), 25 | textStyle: const TextStyle( 26 | fontWeight: FontWeight.w700, 27 | fontSize: 12.0, 28 | letterSpacing: 1.0), 29 | textDirection: TextDirection.ltr, 30 | ) 31 | : safeWidget(context); 32 | } 33 | 34 | Widget safeWidget(BuildContext context) { 35 | return Container( 36 | color: color ?? Theme.of(context).appBarTheme.backgroundColor, 37 | child: SafeArea( 38 | child: Container( 39 | color: Theme.of(context).colorScheme.background, 40 | child: child, 41 | ), 42 | )); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/core/layout/image_placeholder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FadeInImagePlaceHolder extends StatelessWidget { 4 | final ImageProvider image; 5 | final Widget placeholder; 6 | final Widget? child; 7 | final Duration duration; 8 | final bool excludeFromSemantics; 9 | final double? width; 10 | final double? height; 11 | final BoxFit? fit; 12 | 13 | const FadeInImagePlaceHolder({ 14 | Key? key, 15 | required this.image, 16 | required this.placeholder, 17 | this.duration = const Duration(milliseconds: 500), 18 | this.excludeFromSemantics = false, 19 | this.child, 20 | this.width, 21 | this.height, 22 | this.fit, 23 | }) : super(key: key); 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Image( 28 | image: image, 29 | excludeFromSemantics: excludeFromSemantics, 30 | width: width, 31 | height: height, 32 | fit: fit, 33 | frameBuilder: (context, child, frame, wasSynchronouslyLoaded) { 34 | if (wasSynchronouslyLoaded) { 35 | return this.child ?? child; 36 | } else { 37 | return AnimatedSwitcher( 38 | duration: duration, 39 | child: frame != null ? this.child ?? child : placeholder, 40 | ); 41 | } 42 | }, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/core/logger/abstract_logger.dart: -------------------------------------------------------------------------------- 1 | abstract class AbstractLogger { 2 | void d(String message); 3 | 4 | void w(String message); 5 | 6 | void e(Object error); 7 | } 8 | -------------------------------------------------------------------------------- /lib/core/logger/firebase_logger.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_crashlytics/firebase_crashlytics.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'abstract_logger.dart'; 4 | 5 | class FirebaseLogger extends AbstractLogger { 6 | late final FirebaseCrashlytics _crashlytics; 7 | 8 | FirebaseLogger() { 9 | _crashlytics = FirebaseCrashlytics.instance; 10 | } 11 | 12 | @override 13 | void d(String message) { 14 | _crashlytics.log('(D) $message'); 15 | } 16 | 17 | @override 18 | void e(Object error) { 19 | _crashlytics.recordFlutterError(FlutterErrorDetails(exception: error)); 20 | } 21 | 22 | @override 23 | void w(String message) { 24 | _crashlytics.log('(W) $message'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/core/model/categories.dart: -------------------------------------------------------------------------------- 1 | import 'package:drift/drift.dart'; 2 | 3 | @DataClassName('Category') 4 | class Categories extends Table { 5 | IntColumn get id => integer().autoIncrement()(); 6 | 7 | TextColumn get description => text()(); 8 | } 9 | -------------------------------------------------------------------------------- /lib/core/network/network_client.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:dio/dio.dart'; 3 | import '../error/exception.dart'; 4 | import 'dart:async'; 5 | 6 | class NetworkClient { 7 | final Dio dio; 8 | 9 | NetworkClient({required this.dio}); 10 | 11 | Future invoke(String url, RequestType requestType, 12 | {Map? queryParameters, 13 | Map? headers, 14 | dynamic requestBody}) async { 15 | Response response; 16 | try { 17 | switch (requestType) { 18 | case RequestType.get: 19 | response = await dio.get(url, 20 | queryParameters: queryParameters, 21 | options: Options(responseType: ResponseType.json)); 22 | break; 23 | case RequestType.post: 24 | response = await dio.post(url, 25 | queryParameters: queryParameters, 26 | data: requestBody, 27 | options: Options(responseType: ResponseType.json)); 28 | break; 29 | case RequestType.put: 30 | response = await dio.put(url, 31 | data: requestBody, 32 | options: Options(responseType: ResponseType.json)); 33 | break; 34 | case RequestType.delete: 35 | response = await dio.delete(url, 36 | queryParameters: queryParameters, 37 | data: requestBody, 38 | options: Options(responseType: ResponseType.json)); 39 | break; 40 | case RequestType.patch: 41 | response = await dio.patch(url, 42 | queryParameters: queryParameters, 43 | data: requestBody, 44 | options: Options(responseType: ResponseType.json)); 45 | break; 46 | } 47 | return response; 48 | } on DioError catch (dioError) { 49 | throw ServerException(dioError: dioError); 50 | } on SocketException { 51 | rethrow; 52 | } 53 | } 54 | } 55 | 56 | // Types used by invoke API. 57 | enum RequestType { get, post, put, delete, patch } 58 | -------------------------------------------------------------------------------- /lib/core/network/network_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:simple_connection_checker/simple_connection_checker.dart'; 2 | 3 | abstract class NetworkInfo { 4 | Future get isConnected; 5 | 6 | SimpleConnectionChecker get simpleConnectionChecker; 7 | } 8 | 9 | class NetworkInfoImpl extends NetworkInfo { 10 | NetworkInfoImpl(); 11 | 12 | @override 13 | Future get isConnected async { 14 | return await SimpleConnectionChecker.isConnectedToInternet(); 15 | } 16 | 17 | @override 18 | SimpleConnectionChecker get simpleConnectionChecker => 19 | SimpleConnectionChecker(); 20 | } 21 | -------------------------------------------------------------------------------- /lib/core/network/pretty_dio_logger.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | import 'package:dio/dio.dart'; 3 | 4 | class PrettyDioLogger extends Interceptor { 5 | /// Print request [Options] 6 | final bool request; 7 | 8 | /// Print request header [Options.headers] 9 | final bool requestHeader; 10 | 11 | /// Print request data [Options.data] 12 | final bool requestBody; 13 | 14 | /// Print [Response.data] 15 | final bool responseBody; 16 | 17 | /// Print [Response.headers] 18 | final bool responseHeader; 19 | 20 | /// Print error message 21 | final bool error; 22 | 23 | /// InitialTab count to logPrint json response 24 | static const int initialTab = 1; 25 | 26 | /// 1 tab length 27 | static const String tabStep = ' '; 28 | 29 | /// Print compact json response 30 | final bool compact; 31 | 32 | /// Width size per logPrint 33 | final int maxWidth; 34 | 35 | /// Log printer; defaults logPrint log to console. 36 | /// In flutter, you'd better use debugPrint. 37 | /// you can also write log in a file. 38 | void Function(Object object) logPrint; 39 | 40 | PrettyDioLogger( 41 | {this.request = true, 42 | this.requestHeader = false, 43 | this.requestBody = false, 44 | this.responseHeader = false, 45 | this.responseBody = true, 46 | this.error = true, 47 | this.maxWidth = 90, 48 | this.compact = true, 49 | this.logPrint = print}); 50 | 51 | @override 52 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) { 53 | if (request) { 54 | _printRequestHeader(options); 55 | } 56 | if (requestHeader) { 57 | _printMapAsTable(options.queryParameters, header: 'Query Parameters'); 58 | final requestHeaders = {}; 59 | requestHeaders.addAll(options.headers); 60 | requestHeaders['contentType'] = options.contentType?.toString(); 61 | requestHeaders['responseType'] = options.responseType.toString(); 62 | requestHeaders['followRedirects'] = options.followRedirects; 63 | requestHeaders['connectTimeout'] = options.connectTimeout; 64 | requestHeaders['receiveTimeout'] = options.receiveTimeout; 65 | _printMapAsTable(requestHeaders, header: 'Headers'); 66 | _printMapAsTable(options.extra, header: 'Extras'); 67 | } 68 | if (requestBody && options.method != 'GET') { 69 | final dynamic data = options.data; 70 | if (data != null) { 71 | if (data is Map) _printMapAsTable(options.data as Map?, header: 'Body'); 72 | if (data is FormData) { 73 | final formDataMap = {} 74 | ..addEntries(data.fields) 75 | ..addEntries(data.files); 76 | _printMapAsTable(formDataMap, header: 'Form data | ${data.boundary}'); 77 | } else { 78 | _printBlock(data.toString()); 79 | } 80 | } 81 | } 82 | super.onRequest(options, handler); 83 | } 84 | 85 | @override 86 | void onError(DioError err, ErrorInterceptorHandler handler) { 87 | if (error) { 88 | if (err.type == DioErrorType.response) { 89 | final uri = err.response?.requestOptions.uri; 90 | _printBoxed( 91 | header: 92 | 'DioError ║ Status: ${err.response?.statusCode} ${err.response?.statusMessage}', 93 | text: uri.toString()); 94 | if (err.response != null && err.response?.data != null) { 95 | logPrint('╔ ${err.type.toString()}'); 96 | _printResponse(err.response!); 97 | } 98 | _printLine('╚'); 99 | logPrint(''); 100 | } else { 101 | _printBoxed(header: 'DioError ║ ${err.type}', text: err.message); 102 | } 103 | } 104 | super.onError(err, handler); 105 | } 106 | 107 | @override 108 | void onResponse(Response response, ResponseInterceptorHandler handler) { 109 | _printResponseHeader(response); 110 | if (responseHeader) { 111 | final responseHeaders = {}; 112 | response.headers 113 | .forEach((k, list) => responseHeaders[k] = list.toString()); 114 | _printMapAsTable(responseHeaders, header: 'Headers'); 115 | } 116 | 117 | if (responseBody) { 118 | logPrint('╔ Body'); 119 | logPrint('║'); 120 | _printResponse(response); 121 | logPrint('║'); 122 | _printLine('╚'); 123 | } 124 | super.onResponse(response, handler); 125 | } 126 | 127 | void _printBoxed({String? header, String? text}) { 128 | logPrint(''); 129 | logPrint('╔╣ $header'); 130 | logPrint('║ $text'); 131 | _printLine('╚'); 132 | } 133 | 134 | void _printResponse(Response response) { 135 | if (response.data != null) { 136 | if (response.data is Map) { 137 | _printPrettyMap(response.data as Map); 138 | } else if (response.data is List) { 139 | logPrint('║${_indent()}['); 140 | _printList(response.data as List); 141 | logPrint('║${_indent()}['); 142 | } else { 143 | _printBlock(response.data.toString()); 144 | } 145 | } 146 | } 147 | 148 | void _printResponseHeader(Response response) { 149 | final uri = response.requestOptions.uri; 150 | final method = response.requestOptions.method; 151 | _printBoxed( 152 | header: 153 | 'Response ║ $method ║ Status: ${response.statusCode} ${response.statusMessage}', 154 | text: uri.toString()); 155 | } 156 | 157 | void _printRequestHeader(RequestOptions options) { 158 | final uri = options.uri; 159 | final method = options.method; 160 | _printBoxed(header: 'Request ║ $method ', text: uri.toString()); 161 | } 162 | 163 | void _printLine([String pre = '', String suf = '╝']) => 164 | logPrint('$pre${'═' * maxWidth}$suf'); 165 | 166 | void _printKV(String? key, Object? v) { 167 | final pre = '╟ $key: '; 168 | final msg = v.toString(); 169 | 170 | if (pre.length + msg.length > maxWidth) { 171 | logPrint(pre); 172 | _printBlock(msg); 173 | } else { 174 | logPrint('$pre$msg'); 175 | } 176 | } 177 | 178 | void _printBlock(String msg) { 179 | final lines = (msg.length / maxWidth).ceil(); 180 | for (var i = 0; i < lines; ++i) { 181 | logPrint((i >= 0 ? '║ ' : '') + 182 | msg.substring(i * maxWidth, 183 | math.min(i * maxWidth + maxWidth, msg.length))); 184 | } 185 | } 186 | 187 | String _indent([int tabCount = initialTab]) => tabStep * tabCount; 188 | 189 | void _printPrettyMap( 190 | Map data, { 191 | int tabs = initialTab, 192 | bool isListItem = false, 193 | bool isLast = false, 194 | }) { 195 | var _tabs = tabs; 196 | final isRoot = _tabs == initialTab; 197 | final initialIndent = _indent(_tabs); 198 | _tabs++; 199 | 200 | if (isRoot || isListItem) logPrint('║$initialIndent{'); 201 | 202 | data.keys.toList().asMap().forEach((index, dynamic key) { 203 | final isLast = index == data.length - 1; 204 | dynamic value = data[key]; 205 | if (value is String) { 206 | value = '"${value.toString().replaceAll(RegExp(r'(\r|\n)+'), " ")}"'; 207 | } 208 | if (value is Map) { 209 | if (compact && _canFlattenMap(value)) { 210 | logPrint('║${_indent(_tabs)} $key: $value${!isLast ? ',' : ''}'); 211 | } else { 212 | logPrint('║${_indent(_tabs)} $key: {'); 213 | _printPrettyMap(value, tabs: _tabs); 214 | } 215 | } else if (value is List) { 216 | if (compact && _canFlattenList(value)) { 217 | logPrint('║${_indent(_tabs)} $key: ${value.toString()}'); 218 | } else { 219 | logPrint('║${_indent(_tabs)} $key: ['); 220 | _printList(value, tabs: _tabs); 221 | logPrint('║${_indent(_tabs)} ]${isLast ? '' : ','}'); 222 | } 223 | } else { 224 | final msg = value.toString().replaceAll('\n', ''); 225 | final indent = _indent(_tabs); 226 | final linWidth = maxWidth - indent.length; 227 | if (msg.length + indent.length > linWidth) { 228 | final lines = (msg.length / linWidth).ceil(); 229 | for (var i = 0; i < lines; ++i) { 230 | logPrint( 231 | '║${_indent(_tabs)} ${msg.substring(i * linWidth, math.min(i * linWidth + linWidth, msg.length))}'); 232 | } 233 | } else { 234 | logPrint('║${_indent(_tabs)} $key: $msg${!isLast ? ',' : ''}'); 235 | } 236 | } 237 | }); 238 | 239 | logPrint('║$initialIndent}${isListItem && !isLast ? ',' : ''}'); 240 | } 241 | 242 | void _printList(List list, {int tabs = initialTab}) { 243 | list.asMap().forEach((i, dynamic e) { 244 | final isLast = i == list.length - 1; 245 | if (e is Map) { 246 | if (compact && _canFlattenMap(e)) { 247 | logPrint('║${_indent(tabs)} $e${!isLast ? ',' : ''}'); 248 | } else { 249 | _printPrettyMap(e, tabs: tabs + 1, isListItem: true, isLast: isLast); 250 | } 251 | } else { 252 | logPrint('║${_indent(tabs + 2)} $e${isLast ? '' : ','}'); 253 | } 254 | }); 255 | } 256 | 257 | bool _canFlattenMap(Map map) { 258 | return map.values 259 | .where((dynamic val) => val is Map || val is List) 260 | .isEmpty && 261 | map.toString().length < maxWidth; 262 | } 263 | 264 | bool _canFlattenList(List list) { 265 | return list.length < 10 && list.toString().length < maxWidth; 266 | } 267 | 268 | void _printMapAsTable(Map? map, {String? header}) { 269 | if (map == null || map.isEmpty) return; 270 | logPrint('╔ $header '); 271 | map.forEach( 272 | (dynamic key, dynamic value) => _printKV(key.toString(), value)); 273 | _printLine('╚'); 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /lib/core/routing/routes.dart: -------------------------------------------------------------------------------- 1 | import 'package:developine_app/core/bloc/network_cubit.dart'; 2 | import 'package:developine_app/features/home/presentation/pages/home_page.dart'; 3 | import 'package:developine_app/features/login/presentation/cubit/login_cubit.dart'; 4 | import 'package:developine_app/features/splash/splash_page.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_bloc/flutter_bloc.dart'; 7 | import '../../features/login/presentation/pages/login_page.dart'; 8 | import '../../features/search/presentation/pages/search_page.dart'; 9 | import '../const/route_constants.dart'; 10 | import '../di/injection_container.dart'; 11 | 12 | class RouteNavigator { 13 | static final GlobalKey navigatorKey = 14 | GlobalKey(); 15 | 16 | NavigatorState get _navigator => navigatorKey.currentState!; 17 | 18 | static final routesList = { 19 | RoutesList.initialRoute: (context) => SplashPage(), 20 | RoutesList.loginRoute: (context) => LoginPage(), 21 | RoutesList.homeRoute: (context) => HomePage(), 22 | RoutesList.searchRoute: (context) => SearchPage(), 23 | }; 24 | 25 | static Future? pushNamed( 26 | {required String routeName, Arguments? arguments}) { 27 | return navigatorKey.currentState 28 | ?.pushNamed(routeName, arguments: arguments); 29 | } 30 | 31 | static void pop() { 32 | navigatorKey.currentState?.pop(); 33 | } 34 | 35 | static Future? pushRepalcementNamed( 36 | {required String routeName, Arguments? arguments}) { 37 | return navigatorKey.currentState 38 | ?.pushReplacementNamed(routeName, arguments: arguments); 39 | } 40 | 41 | static List> defaultGenerateInitialRoutes( 42 | String initialRouteName) { 43 | List routes = []; 44 | routes 45 | .add(MaterialPageRoute(builder: routesList[RoutesList.initialRoute]!)); 46 | return routes; 47 | } 48 | 49 | static Route generateNamedRoute(RouteSettings settings) { 50 | switch (settings.name) { 51 | case RoutesList.initialRoute: 52 | { 53 | return MaterialPageRoute( 54 | builder: (_) => MultiBlocProvider(providers: [ 55 | BlocProvider( 56 | create: (_) => serviceLocator()), 57 | ], child: SplashPage()), 58 | ); 59 | } 60 | case RoutesList.loginRoute: 61 | { 62 | return MaterialPageRoute( 63 | builder: (_) => MultiBlocProvider(providers: [ 64 | BlocProvider( 65 | create: (_) => serviceLocator()), 66 | ], child: LoginPage()), 67 | ); 68 | } 69 | case RoutesList.homeRoute: 70 | { 71 | return MaterialPageRoute( 72 | builder: (_) => MultiBlocProvider(providers: [ 73 | BlocProvider( 74 | create: (_) => serviceLocator()), 75 | ], child: HomePage()), 76 | ); 77 | } 78 | 79 | case RoutesList.searchRoute: 80 | { 81 | return MaterialPageRoute( 82 | builder: (_) => MultiBlocProvider(providers: [ 83 | BlocProvider( 84 | create: (_) => serviceLocator()), 85 | ], child: SearchPage()), 86 | ); 87 | } 88 | default: 89 | throw Exception('This route name does not exit'); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/core/util/constant.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// LOG TAG 3 | /// 4 | const String kaPILogFlag = ""; 5 | 6 | /// 7 | /// DATABASE NAME 8 | /// 9 | const String kdbName = "developine_data.db"; 10 | 11 | const String CURRENT_LANG_FLAG = ""; 12 | 13 | var kTestingCrashlytics = true; 14 | var kDebugMode = true; 15 | -------------------------------------------------------------------------------- /lib/core/util/location_handler.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:location/location.dart'; 3 | import '../error/failures.dart'; 4 | 5 | class LocationHandler { 6 | bool _serviceEnabled = false; 7 | late PermissionStatus _permissionGranted; 8 | LocationData? _locationData; 9 | 10 | Future> getCurrentLocation() async { 11 | Location location = Location(); 12 | _serviceEnabled = await location.serviceEnabled(); 13 | if (!_serviceEnabled) { 14 | _serviceEnabled = await location.requestService(); 15 | if (!_serviceEnabled) { 16 | return const Left(LocationFailure("", LocationFailureReason.disabled)); 17 | } 18 | } 19 | 20 | _permissionGranted = await location.hasPermission(); 21 | if (_permissionGranted == PermissionStatus.denied) { 22 | _permissionGranted = (await location.requestPermission()); 23 | if (_permissionGranted != PermissionStatus.granted) { 24 | return const Left(LocationFailure("", LocationFailureReason.denied)); 25 | } 26 | } 27 | _locationData = (await location.getLocation()); 28 | return Right(_locationData); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/core/util/string_apis.dart: -------------------------------------------------------------------------------- 1 | // Extentsion function. 2 | extension NumberParsing on String { 3 | String parseDouble(int decimal) { 4 | return double.parse(this).toStringAsFixed(decimal); 5 | } 6 | 7 | int parseInt() { 8 | return int.parse(this); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/core/util/theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_fonts/google_fonts.dart'; 3 | 4 | // Colors 5 | const Color primaryColor = Color(0xFF6200EE); 6 | const Color primaryVariantColor = Color(0xFF3700B3); 7 | const Color secondaryColor = Color(0xFF03DAC6); 8 | const Color secondaryVariantColor = Color(0xFF018786); 9 | const Color backgroundColor = Color(0xFFFFFFFF); 10 | const Color surfaceColor = Color(0xFFFFFFFF); 11 | const Color errorColor = Color(0xFFB00020); 12 | const Color onPrimaryColor = Color(0xFFFFFFFF); 13 | const Color onSecondaryColor = Color(0xFF000000); 14 | const Color onBackgroundColor = Color(0xFF000000); 15 | const Color onSurfaceColor = Color(0xFF000000); 16 | const Color onErrorColor = Color(0xFF000000); 17 | const Color dividerColor = Color(0xFFFF7F41); 18 | 19 | // Padding 20 | const double kPaddingS = 8.0; 21 | const double kPaddingM = 16.0; 22 | const double kPaddingL = 24.0; 23 | 24 | // Spacing 25 | const double kSpaceS = 8.0; 26 | const double kSpaceM = 12.0; 27 | const double kSpaceL = 16.0; 28 | 29 | const double kRadiusM = 16.0; 30 | 31 | // Spacing 32 | const double kIconS = 24.0; 33 | const double kIconM = 36.0; 34 | const double kIconL = 48.0; 35 | 36 | // Animation 37 | const Duration kButtonAnimationDuration = Duration(milliseconds: 600); 38 | const Duration kCardAnimationDuration = Duration(milliseconds: 400); 39 | const Duration kRippleAnimationDuration = Duration(milliseconds: 400); 40 | const Duration kLoginAnimationDuration = Duration(milliseconds: 1500); 41 | 42 | // Text Styling 43 | 44 | TextStyle headline2 = GoogleFonts.raleway( 45 | textStyle: const TextStyle( 46 | fontSize: 60, 47 | color: onBackgroundColor, 48 | fontWeight: FontWeight.normal, 49 | ), 50 | ); 51 | TextStyle headline3 = GoogleFonts.raleway( 52 | textStyle: const TextStyle( 53 | fontSize: 48, 54 | color: onBackgroundColor, 55 | fontWeight: FontWeight.normal, 56 | ), 57 | ); 58 | TextStyle headline4 = GoogleFonts.raleway( 59 | textStyle: const TextStyle( 60 | fontSize: 34, 61 | color: onBackgroundColor, 62 | fontWeight: FontWeight.normal, 63 | ), 64 | ); 65 | TextStyle headline5 = GoogleFonts.raleway( 66 | textStyle: const TextStyle( 67 | fontSize: 24, 68 | color: onBackgroundColor, 69 | fontWeight: FontWeight.normal, 70 | ), 71 | ); 72 | TextStyle headline6 = GoogleFonts.raleway( 73 | textStyle: const TextStyle( 74 | fontSize: 20, 75 | letterSpacing: 0.15, 76 | color: onBackgroundColor, 77 | fontWeight: FontWeight.w700, 78 | ), 79 | ); 80 | TextStyle body1 = GoogleFonts.raleway( 81 | textStyle: const TextStyle( 82 | fontSize: 16, 83 | color: onBackgroundColor, 84 | fontWeight: FontWeight.normal, 85 | ), 86 | ); 87 | TextStyle body2 = GoogleFonts.raleway( 88 | textStyle: const TextStyle( 89 | fontSize: 14, 90 | color: onBackgroundColor, 91 | fontWeight: FontWeight.normal, 92 | ), 93 | ); 94 | TextStyle button = GoogleFonts.raleway( 95 | textStyle: const TextStyle( 96 | fontSize: 14, 97 | color: onPrimaryColor, 98 | fontWeight: FontWeight.w700, 99 | ), 100 | ); 101 | TextStyle caption = GoogleFonts.raleway( 102 | textStyle: const TextStyle( 103 | fontSize: 12, 104 | color: onBackgroundColor, 105 | fontWeight: FontWeight.normal, 106 | ), 107 | ); 108 | TextStyle subTitle1 = GoogleFonts.raleway( 109 | textStyle: const TextStyle( 110 | fontSize: 16, 111 | color: onBackgroundColor, 112 | fontWeight: FontWeight.normal, 113 | ), 114 | ); 115 | TextStyle subTitle2 = GoogleFonts.raleway( 116 | textStyle: const TextStyle( 117 | fontSize: 14, 118 | color: onBackgroundColor, 119 | fontWeight: FontWeight.normal, 120 | ), 121 | ); 122 | TextStyle overline = GoogleFonts.raleway( 123 | textStyle: const TextStyle( 124 | fontSize: 14, 125 | color: onBackgroundColor, 126 | fontWeight: FontWeight.normal, 127 | ), 128 | ); 129 | 130 | InputDecoration kTextFieldDecoration = InputDecoration( 131 | hintText: 'Milk, water, bread, oil, tomatto...', 132 | fillColor: onPrimaryColor, 133 | hintStyle: body2, 134 | filled: true, 135 | contentPadding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0), 136 | suffixIcon: Icon( 137 | Icons.search, 138 | color: primaryColor, 139 | ), 140 | suffixIconColor: primaryColor, 141 | border: OutlineInputBorder( 142 | borderRadius: BorderRadius.all(Radius.circular(kRadiusM)), 143 | ), 144 | enabledBorder: OutlineInputBorder( 145 | borderSide: BorderSide(color: Colors.blueAccent, width: 0), 146 | borderRadius: BorderRadius.all(Radius.circular(kRadiusM)), 147 | ), 148 | focusedBorder: OutlineInputBorder( 149 | borderSide: BorderSide(color: Colors.blueAccent, width: 0), 150 | borderRadius: BorderRadius.all(Radius.circular(kRadiusM)), 151 | ), 152 | ); 153 | 154 | // Light Theme 155 | ThemeData lightTheme = ThemeData.light().copyWith( 156 | primaryColor: primaryColor, 157 | primaryColorDark: primaryColor, 158 | secondaryHeaderColor: secondaryColor, 159 | canvasColor: Colors.transparent, 160 | brightness: Brightness.dark, 161 | errorColor: errorColor, 162 | backgroundColor: backgroundColor, 163 | textTheme: TextTheme( 164 | subtitle1: subTitle1, 165 | subtitle2: subTitle2, 166 | bodyText1: body1, 167 | bodyText2: body2, 168 | caption: caption, 169 | overline: overline, 170 | headline6: headline6, 171 | headline5: headline5, 172 | headline4: headline4, 173 | headline3: headline3, 174 | ), 175 | inputDecorationTheme: const InputDecorationTheme(), 176 | appBarTheme: const AppBarTheme( 177 | color: primaryColor, 178 | actionsIconTheme: IconThemeData(color: Colors.white)), 179 | colorScheme: ColorScheme.fromSwatch().copyWith(secondary: secondaryColor)); 180 | 181 | // Dark Theme. 182 | ThemeData darkTheme = ThemeData.dark() 183 | .copyWith(brightness: Brightness.dark, backgroundColor: Colors.blue[700]); 184 | -------------------------------------------------------------------------------- /lib/core/util/theme_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:get/get.dart'; 4 | import 'package:get_it/get_it.dart'; 5 | import 'package:shared_preferences/shared_preferences.dart'; 6 | 7 | import 'constant.dart'; 8 | 9 | class ThemeController extends GetxController { 10 | // initializing through service locator. 11 | var sharedPreferences = GetIt.I(); 12 | 13 | late ThemeMode _themeMode; 14 | 15 | // ThemeMode.Getter 16 | ThemeMode get themeMode => _themeMode; 17 | 18 | Future setThemeMode(ThemeMode themeMode) async { 19 | Get.changeThemeMode(themeMode); 20 | _themeMode = themeMode; 21 | update(); 22 | await sharedPreferences.setString( 23 | CURRENT_LANG_FLAG, themeMode.toString().split('.')[1]); 24 | } 25 | 26 | /// Get User preferred theme mode and set it by default. 27 | getThemeModePreferences() async { 28 | ThemeMode themeMode; 29 | // Get System as default theme. 30 | String themeTxt = 31 | sharedPreferences.getString(CURRENT_LANG_FLAG) ?? 'System'; 32 | try { 33 | themeMode = ThemeMode.values 34 | .firstWhere((element) => describeEnum(element) == themeTxt); 35 | } catch (exception) { 36 | themeMode = ThemeMode.system; 37 | exception.printError(); 38 | } 39 | setThemeMode(themeMode); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/core/util/utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | class Utils { 4 | static String get currentDateTime => DateTime.now().toString(); 5 | 6 | static Color fromHex(String hexString) { 7 | final buffer = StringBuffer(); 8 | if (hexString.length == 6 || hexString.length == 7) buffer.write('ff'); 9 | buffer.write(hexString.replaceFirst('#', '')); 10 | return Color(int.parse(buffer.toString(), radix: 16)); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/core/util/validation.dart: -------------------------------------------------------------------------------- 1 | // check if email is valid using regex. 2 | bool isValidEmail(String email) { 3 | Pattern pattern = 4 | r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'; 5 | RegExp regex = RegExp(pattern.toString()); 6 | return (!regex.hasMatch(email)) ? false : true; 7 | } 8 | 9 | bool isPasswordValid(String value, String countryCode) { 10 | switch (countryCode) { 11 | case 'AE': 12 | return value.length >= 8; 13 | case 'BH': 14 | return value.length >= 8; 15 | default: 16 | return value.length >= 8; 17 | } 18 | } 19 | 20 | bool doPasswordsMatch(String password, String passwordConfirm) => 21 | (password == passwordConfirm); 22 | -------------------------------------------------------------------------------- /lib/features/cart/data/local/data_sources/cart_local_datasource.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/cart/data/local/data_sources/cart_local_datasource.dart -------------------------------------------------------------------------------- /lib/features/cart/data/remote/data_sources/cart_remote_datasource.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/cart/data/remote/data_sources/cart_remote_datasource.dart -------------------------------------------------------------------------------- /lib/features/cart/data/repositories/cart_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/cart_repository.dart'; 2 | 3 | class CartRepoImpl implements CartRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/cart/domain/repositories/cart_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class CartRepository {} 2 | -------------------------------------------------------------------------------- /lib/features/cart/presentation/manager/cart_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | part 'cart_event.dart'; 5 | 6 | part 'cart_state.dart'; 7 | 8 | class CartBloc extends Bloc { 9 | CartBloc() : super(CartInitial()) { 10 | on((event, emit) { 11 | // TODO: implement event handler 12 | }); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/features/cart/presentation/manager/cart_event.dart: -------------------------------------------------------------------------------- 1 | part of 'cart_bloc.dart'; 2 | 3 | abstract class CartEvent extends Equatable { 4 | const CartEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/cart/presentation/manager/cart_state.dart: -------------------------------------------------------------------------------- 1 | part of 'cart_bloc.dart'; 2 | 3 | abstract class CartState extends Equatable { 4 | const CartState(); 5 | } 6 | 7 | class CartInitial extends CartState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/cart/presentation/pages/cart_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CartPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return CartPageState(); 7 | } 8 | } 9 | 10 | class CartPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | // TODO: implement build 19 | throw UnimplementedError(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/categories/data/data_sources/categories_remote_datasource.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/categories/data/data_sources/categories_remote_datasource.dart -------------------------------------------------------------------------------- /lib/features/categories/data/models/categories_ model.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/categories/data/models/categories_ model.dart -------------------------------------------------------------------------------- /lib/features/categories/data/repositories/categories_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/categories_repo.dart'; 2 | 3 | class CategoriesRepoImpl implements CategoriesRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/categories/domain/repositories/categories_repo.dart: -------------------------------------------------------------------------------- 1 | abstract class CategoriesRepository {} 2 | -------------------------------------------------------------------------------- /lib/features/categories/presentation/manager/categories_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | part 'categories_event.dart'; 5 | part 'categories_state.dart'; 6 | 7 | class CategoriesBloc extends Bloc { 8 | CategoriesBloc() : super(CategoriesInitial()) { 9 | on((event, emit) { 10 | // TODO: implement event handler 11 | }); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/categories/presentation/manager/categories_event.dart: -------------------------------------------------------------------------------- 1 | part of 'categories_bloc.dart'; 2 | 3 | abstract class CategoriesEvent extends Equatable { 4 | const CategoriesEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/categories/presentation/manager/categories_state.dart: -------------------------------------------------------------------------------- 1 | part of 'categories_bloc.dart'; 2 | 3 | abstract class CategoriesState extends Equatable { 4 | const CategoriesState(); 5 | } 6 | 7 | class CategoriesInitial extends CategoriesState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/categories/presentation/pages/categories_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CategoriesPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return CategoriesPageState(); 7 | } 8 | } 9 | 10 | class CategoriesPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | // TODO: implement build 19 | throw UnimplementedError(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/checkout/data/data_sources/checkout_remote_datasource.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/checkout/data/data_sources/checkout_remote_datasource.dart -------------------------------------------------------------------------------- /lib/features/checkout/data/models/checkout_model.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/checkout/data/models/checkout_model.dart -------------------------------------------------------------------------------- /lib/features/checkout/data/repositories/checkout_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/checkout_repo.dart'; 2 | 3 | class CheckoutRepoImpl implements CheckOutRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/checkout/domain/repositories/checkout_repo.dart: -------------------------------------------------------------------------------- 1 | abstract class CheckOutRepository {} -------------------------------------------------------------------------------- /lib/features/checkout/presentation/manager/checkout_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | part 'checkout_event.dart'; 5 | part 'checkout_state.dart'; 6 | 7 | class CheckoutBloc extends Bloc { 8 | CheckoutBloc() : super(CheckoutInitial()) { 9 | on((event, emit) { 10 | // TODO: implement event handler 11 | }); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/manager/checkout_event.dart: -------------------------------------------------------------------------------- 1 | part of 'checkout_bloc.dart'; 2 | 3 | abstract class CheckoutEvent extends Equatable { 4 | const CheckoutEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/manager/checkout_state.dart: -------------------------------------------------------------------------------- 1 | part of 'checkout_bloc.dart'; 2 | 3 | abstract class CheckoutState extends Equatable { 4 | const CheckoutState(); 5 | } 6 | 7 | class CheckoutInitial extends CheckoutState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/pages/checkout_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CheckoutPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return CheckoutPageState(); 7 | } 8 | } 9 | 10 | class CheckoutPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | // TODO: implement build 19 | throw UnimplementedError(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/detail/data/data_sources/detail_remote_datasource.dart: -------------------------------------------------------------------------------- 1 | class DetailRemoteDataSource {} 2 | -------------------------------------------------------------------------------- /lib/features/detail/data/repositories/detail_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/detail_repository.dart'; 2 | 3 | class DetailRepoImpl implements DetailRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/detail/domain/repositories/detail_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class DetailRepository {} 2 | -------------------------------------------------------------------------------- /lib/features/detail/presentation/manager/detail_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | part 'detail_event.dart'; 5 | part 'detail_state.dart'; 6 | 7 | class DetailBloc extends Bloc { 8 | DetailBloc() : super(DetailInitial()) { 9 | on((event, emit) { 10 | // TODO: implement event handler 11 | }); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/detail/presentation/manager/detail_event.dart: -------------------------------------------------------------------------------- 1 | part of 'detail_bloc.dart'; 2 | 3 | abstract class DetailEvent extends Equatable { 4 | const DetailEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/detail/presentation/manager/detail_state.dart: -------------------------------------------------------------------------------- 1 | part of 'detail_bloc.dart'; 2 | 3 | abstract class DetailState extends Equatable { 4 | const DetailState(); 5 | } 6 | 7 | class DetailInitial extends DetailState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/detail/presentation/pages/detail_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DetailPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return DetailPageState(); 7 | } 8 | } 9 | 10 | class DetailPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | void dispose() { 18 | super.dispose(); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | // TODO: implement build 24 | throw UnimplementedError(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/faqs/faqs_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FaqsPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return FaqsPageState(); 7 | } 8 | } 9 | 10 | class FaqsPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | void dispose() { 18 | super.dispose(); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | // TODO: implement build 24 | throw UnimplementedError(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/history/data/repositories/history_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/history_repository.dart'; 2 | 3 | class HistoryRepoImpl implements HistoryRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/history/domain/repositories/history_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class HistoryRepository {} 2 | -------------------------------------------------------------------------------- /lib/features/history/presentation/manager/history_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | part 'history_event.dart'; 5 | part 'history_state.dart'; 6 | 7 | class HistoryBloc extends Bloc { 8 | HistoryBloc() : super(HistoryInitial()) { 9 | on((event, emit) { 10 | // TODO: implement event handler 11 | }); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/history/presentation/manager/history_event.dart: -------------------------------------------------------------------------------- 1 | part of 'history_bloc.dart'; 2 | 3 | abstract class HistoryEvent extends Equatable { 4 | const HistoryEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/history/presentation/manager/history_state.dart: -------------------------------------------------------------------------------- 1 | part of 'history_bloc.dart'; 2 | 3 | abstract class HistoryState extends Equatable { 4 | const HistoryState(); 5 | } 6 | 7 | class HistoryInitial extends HistoryState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/history/presentation/pages/history_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class HistoryPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return HistoryPageState(); 7 | } 8 | } 9 | 10 | class HistoryPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | void dispose() { 18 | super.dispose(); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | // TODO: implement build 24 | throw UnimplementedError(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/home/data/data_sources/home_remote_datasource.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/home/data/data_sources/home_remote_datasource.dart -------------------------------------------------------------------------------- /lib/features/home/data/models/home_model.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/home/data/models/home_model.dart -------------------------------------------------------------------------------- /lib/features/home/data/repositories/home_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/home_repo.dart'; 2 | 3 | class HomeRepoImpl implements HomeRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/home/domain/repositories/home_repo.dart: -------------------------------------------------------------------------------- 1 | abstract class HomeRepository {} -------------------------------------------------------------------------------- /lib/features/home/presentation/manager/home_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | part 'home_event.dart'; 5 | part 'home_state.dart'; 6 | 7 | class HomeBloc extends Bloc { 8 | HomeBloc() : super(HomeInitial()) { 9 | on((event, emit) { 10 | // TODO: implement event handler 11 | }); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/home/presentation/manager/home_event.dart: -------------------------------------------------------------------------------- 1 | part of 'home_bloc.dart'; 2 | 3 | abstract class HomeEvent extends Equatable { 4 | const HomeEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/home/presentation/manager/home_state.dart: -------------------------------------------------------------------------------- 1 | part of 'home_bloc.dart'; 2 | 3 | abstract class HomeState extends Equatable { 4 | const HomeState(); 5 | } 6 | 7 | class HomeInitial extends HomeState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/home/presentation/pages/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:developine_app/core/layout/colored_safearea.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/rendering.dart'; 4 | import '../../../../core/util/theme.dart'; 5 | import '../widgets/header_menu_widget.dart'; 6 | import '../widgets/search_field_widget.dart'; 7 | 8 | class HomePage extends StatefulWidget { 9 | @override 10 | State createState() { 11 | return HomePageState(); 12 | } 13 | } 14 | 15 | class HomePageState extends State { 16 | @override 17 | void initState() { 18 | super.initState(); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return ColoredSafeArea( 24 | child: Scaffold( 25 | body: Padding( 26 | padding: const EdgeInsets.only( 27 | top: kPaddingS, left: kPaddingS, right: kPaddingS), 28 | child: Column( 29 | crossAxisAlignment: CrossAxisAlignment.center, 30 | mainAxisAlignment: MainAxisAlignment.start, 31 | children: [ 32 | HeaderMenuWidget(), 33 | SizedBox( 34 | height: kSpaceS, 35 | ), 36 | Text( 37 | 'We will deliver in 30 minutes', 38 | style: subTitle2, 39 | ), 40 | SizedBox( 41 | height: kSpaceM, 42 | ), 43 | SearchFieldWidget(), 44 | ], 45 | ), 46 | ), 47 | ), 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/features/home/presentation/widgets/header_menu_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | import '../../../../core/util/theme.dart'; 5 | 6 | class HeaderMenuWidget extends StatelessWidget { 7 | @override 8 | Widget build(BuildContext context) { 9 | return Row( 10 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 11 | children: [ 12 | Icon( 13 | Icons.card_giftcard, 14 | size: kIconM, 15 | ), 16 | Flexible( 17 | child: Text( 18 | 'The Gardens appartment 1 ', 19 | style: headline6, 20 | ), 21 | ), 22 | Icon( 23 | Icons.person, 24 | size: kIconM, 25 | ), 26 | ], 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/features/home/presentation/widgets/search_field_widget.dart: -------------------------------------------------------------------------------- 1 | import 'dart:developer'; 2 | import 'package:developine_app/core/const/route_constants.dart'; 3 | import 'package:developine_app/core/routing/routes.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/widgets.dart'; 6 | import '../../../../core/util/theme.dart'; 7 | 8 | class SearchFieldWidget extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return InkWell( 12 | child: TextField( 13 | decoration: kTextFieldDecoration, 14 | enabled: false, 15 | ), 16 | onTap: () { 17 | log("Search Icon tap."); 18 | RouteNavigator.pushNamed(routeName: RoutesList.searchRoute); 19 | }, 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/features/listing/data/data_sources/user_list_local_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:shared_preferences/shared_preferences.dart'; 3 | import '../models/user_model.dart'; 4 | 5 | abstract class UserListLocalDataSource { 6 | // Get the cached [UserModel] 7 | // throws exception if no data found. 8 | Future? getUsersList(); 9 | 10 | Future saveUsersList(UserModel userModel); 11 | } 12 | 13 | const CACHED_USER_LIST = 'CACHED_USER_LIST'; 14 | 15 | class UserListLocalDataSourceImpl implements UserListLocalDataSource { 16 | final SharedPreferences sharedPreferences; 17 | 18 | UserListLocalDataSourceImpl({required this.sharedPreferences}); 19 | 20 | @override 21 | Future? getUsersList() { 22 | final jsonString = sharedPreferences.get(CACHED_USER_LIST); 23 | if (jsonString != null) { 24 | return Future.value( 25 | UserModel.fromJson(json.decode(jsonString.toString()))); 26 | } else { 27 | // TODO: return exception. 28 | return null; 29 | } 30 | } 31 | 32 | @override 33 | Future saveUsersList(UserModel userModel) { 34 | return sharedPreferences.setString( 35 | CACHED_USER_LIST, json.encode(userModel.toJson())); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/features/listing/data/models/user_model.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/entities/user.dart'; 2 | 3 | class UserModel extends User { 4 | UserModel( 5 | {required int id, 6 | required String email, 7 | required String firstName, 8 | required String lastName, 9 | required String avatar}) 10 | : super( 11 | id: id, 12 | email: email, 13 | firstName: firstName, 14 | lastName: lastName, 15 | avatar: avatar); 16 | 17 | factory UserModel.fromJson(Map json) { 18 | return UserModel( 19 | id: json['id'], 20 | email: json['email'], 21 | firstName: json['lastName'], 22 | lastName: json['lastName'], 23 | avatar: json['avatar']); 24 | } 25 | 26 | Map toJson() { 27 | return { 28 | 'id': id, 29 | 'email': email, 30 | 'firstName': firstName, 31 | 'lastName': lastName, 32 | 'avatar': avatar 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/features/listing/data/repositories/user_list_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import '../../domain/entities/user.dart'; 3 | import '../../domain/repositories/user_list_repository.dart'; 4 | 5 | class UserListRepositoryImpl extends UserListRepository { 6 | UserListRepositoryImpl(); 7 | 8 | @override 9 | Future>? getUserList() { 10 | // TODO: implement getUserList 11 | return null; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/listing/domain/entities/user.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class User extends Equatable { 4 | final int id; 5 | final String email; 6 | final String firstName; 7 | final String lastName; 8 | final String avatar; 9 | 10 | User( 11 | {required this.id, 12 | required this.email, 13 | required this.firstName, 14 | required this.lastName, 15 | required this.avatar}); 16 | 17 | @override 18 | List get props => [id, email, firstName, lastName, avatar]; 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/listing/domain/repositories/user_list_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import '../entities/user.dart'; 3 | 4 | abstract class UserListRepository { 5 | Future>? getUserList(); 6 | } 7 | -------------------------------------------------------------------------------- /lib/features/listing/presentation/cubit/listing_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | part 'listing_state.dart'; 5 | 6 | class ListingCubit extends Cubit { 7 | ListingCubit() : super(ListingInitial()); 8 | } 9 | -------------------------------------------------------------------------------- /lib/features/listing/presentation/cubit/listing_state.dart: -------------------------------------------------------------------------------- 1 | part of 'listing_cubit.dart'; 2 | 3 | abstract class ListingState extends Equatable { 4 | const ListingState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class ListingInitial extends ListingState {} 11 | -------------------------------------------------------------------------------- /lib/features/listing/presentation/pages/listing_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../widgets/customer_list.dart'; 3 | import '../widgets/search_field.dart'; 4 | 5 | class ListingPage extends StatefulWidget { 6 | @override 7 | _ListingPageState createState() => _ListingPageState(); 8 | } 9 | 10 | class _ListingPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: AppBar( 20 | centerTitle: true, 21 | title: Text('Customer listing'), 22 | ), 23 | body: Container( 24 | child: Column( 25 | children: [ 26 | SearchField(), 27 | Expanded(child: CustomerList()), 28 | ], 29 | ), 30 | ), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/features/listing/presentation/widgets/customer_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'customer_card_item.dart'; 3 | 4 | class CustomerCard extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Card( 8 | elevation: 8.0, 9 | margin: EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0), 10 | child: Container( 11 | decoration: BoxDecoration(color: Color.fromRGBO(64, 75, 96, .9)), 12 | child: CustomerCardItem(), 13 | ), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/features/listing/presentation/widgets/customer_card_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CustomerCardItem extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return ListTile( 7 | contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), 8 | leading: Container( 9 | padding: EdgeInsets.only(right: 12.0), 10 | decoration: new BoxDecoration( 11 | border: new Border( 12 | right: new BorderSide(width: 1.0, color: Colors.white24))), 13 | child: Icon(Icons.person, color: Colors.white), 14 | ), 15 | title: Text( 16 | "Customer Title", 17 | style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), 18 | ), 19 | // subtitle: Text("Intermediate", style: TextStyle(color: Colors.white)), 20 | 21 | subtitle: Row( 22 | children: [ 23 | Icon(Icons.linear_scale, color: Colors.yellowAccent), 24 | Text("Customer Details", style: TextStyle(color: Colors.white)) 25 | ], 26 | ), 27 | trailing: 28 | Icon(Icons.keyboard_arrow_right, color: Colors.white, size: 30.0)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/listing/presentation/widgets/customer_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'customer_card.dart'; 3 | 4 | class CustomerList extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Container( 8 | child: ListView.builder( 9 | scrollDirection: Axis.vertical, 10 | shrinkWrap: true, 11 | itemCount: 10, 12 | itemBuilder: (BuildContext context, int index) { 13 | return CustomerCard(); 14 | }, 15 | )); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/features/listing/presentation/widgets/search_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../../../../core/util/theme.dart'; 3 | 4 | class SearchField extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Padding( 8 | padding: const EdgeInsets.all(8.0), 9 | child: TextField( 10 | onChanged: (value) { 11 | // TODO: implement callback. 12 | }, 13 | style: headline2, 14 | decoration: InputDecoration( 15 | labelText: "Search", 16 | hintText: "Search", 17 | prefixIcon: Icon(Icons.search), 18 | border: OutlineInputBorder( 19 | borderRadius: BorderRadius.all(Radius.circular(25.0)))), 20 | ), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/location/data/data_sources/location_remote_datasource.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/location/data/data_sources/location_remote_datasource.dart -------------------------------------------------------------------------------- /lib/features/location/data/models/location_model.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/location/data/models/location_model.dart -------------------------------------------------------------------------------- /lib/features/location/data/repositories/location_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/location_repo.dart'; 2 | 3 | class LocationRepoImpl implements LocationRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/location/domain/repositories/location_repo.dart: -------------------------------------------------------------------------------- 1 | abstract class LocationRepository {} 2 | -------------------------------------------------------------------------------- /lib/features/location/presentation/manager/location_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | 6 | part 'location_event.dart'; 7 | part 'location_state.dart'; 8 | 9 | class LocationBloc extends Bloc { 10 | LocationBloc() : super(LocationInitial()) { 11 | on((event, emit) { 12 | // TODO: implement event handler 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/location/presentation/manager/location_event.dart: -------------------------------------------------------------------------------- 1 | part of 'location_bloc.dart'; 2 | 3 | abstract class LocationEvent extends Equatable { 4 | const LocationEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/location/presentation/manager/location_state.dart: -------------------------------------------------------------------------------- 1 | part of 'location_bloc.dart'; 2 | 3 | abstract class LocationState extends Equatable { 4 | const LocationState(); 5 | } 6 | 7 | class LocationInitial extends LocationState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/location/presentation/pages/deliverylocation_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DeliveryLocationPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return DeliveryLocationPageState(); 7 | } 8 | } 9 | 10 | class DeliveryLocationPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | throw UnimplementedError(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/login/data/data_sources/login_local_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | import '../models/login_response_model.dart'; 3 | 4 | abstract class LoginLocalDataSource { 5 | Future getUserProfile(); 6 | 7 | Future saveUserProfile(); 8 | } 9 | 10 | class LoginLocalDataSourceImpl implements LoginLocalDataSource { 11 | final SharedPreferences sharedPreferences; 12 | 13 | LoginLocalDataSourceImpl({required this.sharedPreferences}); 14 | 15 | @override 16 | Future getUserProfile() async { 17 | // TODO: implement getUserProfile 18 | return null; 19 | } 20 | 21 | @override 22 | Future saveUserProfile() async { 23 | // TODO: implement saveUserProfile 24 | return null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/login/data/data_sources/login_remote_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import '../../../../core/error/exception.dart'; 3 | import '../../../../core/network/network_client.dart'; 4 | import '../../../../core/const/network_constants.dart'; 5 | import '../../domain/repositories/login_repository.dart'; 6 | import '../models/login_response_model.dart'; 7 | 8 | abstract class LoginRemoteDataSource { 9 | Future makeLoginRequest(LoginRequest loginRequest); 10 | } 11 | 12 | class LoginRemoteDataSourceImpl implements LoginRemoteDataSource { 13 | final NetworkClient networkClient; 14 | 15 | LoginRemoteDataSourceImpl({required this.networkClient}); 16 | 17 | @override 18 | Future makeLoginRequest(LoginRequest loginRequest) async { 19 | Map? params; 20 | LoginResponseModel loginResponseModel; 21 | Response response = await networkClient.invoke(kloginAPI, RequestType.post, 22 | queryParameters: params, requestBody: loginRequest); 23 | if (response.statusCode == 200 || response.statusCode == 201) { 24 | return LoginResponseModel.fromJson(response.data); 25 | } else { 26 | throw ServerException( 27 | dioError: DioError( 28 | error: response, 29 | type: DioErrorType.response, 30 | requestOptions: response.requestOptions), 31 | ); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/features/login/data/models/login_response_model.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/entities/login_response.dart'; 2 | 3 | class LoginResponseModel extends LoginResponseDto { 4 | LoginResponseModel( 5 | {required String name, 6 | required String iBan, 7 | required String activationDate}) 8 | : super(name: name, iBan: iBan, activationDate: activationDate); 9 | 10 | factory LoginResponseModel.fromJson(Map json) { 11 | return LoginResponseModel( 12 | name: json['name'], 13 | iBan: json['iBan'], 14 | activationDate: json['activationDate']); 15 | } 16 | 17 | Map toJson() { 18 | return { 19 | 'name': name, 20 | 'iBan': iBan, 21 | 'activationDate': activationDate, 22 | }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/login/data/repositories/login_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import '../../../../core/error/exception.dart'; 3 | import '../../../../core/network/network_info.dart'; 4 | import '../../domain/repositories/login_repository.dart'; 5 | import '../data_sources/login_local_datasource.dart'; 6 | import '../data_sources/login_remote_datasource.dart'; 7 | import '../models/login_response_model.dart'; 8 | 9 | class LoginRepositoryImpl implements LoginRepository { 10 | final LoginRemoteDataSource loginRemoteDataSourceImpl; 11 | final NetworkInfo networkInfoImpl; 12 | final LoginLocalDataSource loginLocalDataSourceImpl; 13 | 14 | LoginRepositoryImpl( 15 | {required this.loginLocalDataSourceImpl, 16 | required this.networkInfoImpl, 17 | required this.loginRemoteDataSourceImpl}); 18 | 19 | @override 20 | Future> makeLoginRequest( 21 | LoginRequest loginRequest) async { 22 | var loginResponse; 23 | if (await networkInfoImpl.isConnected) { 24 | try { 25 | loginResponse = 26 | await loginRemoteDataSourceImpl.makeLoginRequest(loginRequest); 27 | return Right(loginResponse); 28 | } on ServerException catch (exception) { 29 | return Left(ServerException(dioError: exception.dioError)); 30 | } 31 | } else { 32 | return Left(NoInternetException(message: "no_internet_connection")); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/features/login/domain/entities/login_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class LoginResponseDto extends Equatable { 4 | final String name; 5 | final String iBan; 6 | final String activationDate; 7 | 8 | LoginResponseDto( 9 | {required this.name, required this.iBan, required this.activationDate}); 10 | 11 | @override 12 | List get props => [name, iBan, activationDate]; 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/login/domain/repositories/login_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | import '../../data/models/login_response_model.dart'; 4 | 5 | abstract class LoginRepository { 6 | Future> makeLoginRequest( 7 | LoginRequest loginRequest); 8 | } 9 | 10 | class LoginRequest extends Equatable { 11 | final String? email; 12 | final String? password; 13 | 14 | const LoginRequest({this.email, this.password}); 15 | 16 | factory LoginRequest.fromJson(Map json) => LoginRequest( 17 | email: json['email'] as String?, 18 | password: json['password'] as String?, 19 | ); 20 | 21 | Map toJson() => { 22 | 'email': email, 23 | 'password': password, 24 | }; 25 | 26 | @override 27 | bool get stringify => true; 28 | 29 | @override 30 | List get props => [email, password]; 31 | } 32 | -------------------------------------------------------------------------------- /lib/features/login/presentation/cubit/login_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import '../../../../core/bloc/base_cubit.dart'; 3 | import '../../data/repositories/login_repository_impl.dart'; 4 | import '../../domain/repositories/login_repository.dart'; 5 | 6 | part 'login_state.dart'; 7 | 8 | class LoginCubit extends BaseCubit { 9 | final LoginRepository loginRepository; 10 | 11 | LoginCubit({required this.loginRepository}) : super(LoginInitialState()); 12 | 13 | void authenticateUserApi() async { 14 | emit(LoginInProgressState()); 15 | LoginRequest loginRequest = 16 | LoginRequest(email: "test@email.com", password: "test12345"); 17 | // var loginResponse = await loginRepository.makeLoginRequest(loginRequest); 18 | // 19 | // loginResponse.fold((left) { 20 | // // Failure 21 | // emit(LoginFailureState(message: handleException(left))); 22 | // }, (right) { 23 | // // Success. 24 | // }); 25 | // 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/features/login/presentation/cubit/login_state.dart: -------------------------------------------------------------------------------- 1 | part of 'login_cubit.dart'; 2 | 3 | abstract class LoginState extends Equatable { 4 | const LoginState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class LoginInitialState extends LoginState {} 11 | 12 | class LoginFailureState extends LoginState { 13 | final String message; 14 | 15 | const LoginFailureState({required this.message}); 16 | } 17 | 18 | class LoginSuccessfulState extends LoginState {} 19 | 20 | class LoginInProgressState extends LoginState {} 21 | -------------------------------------------------------------------------------- /lib/features/login/presentation/pages/login_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:developine_app/core/bloc/network_cubit.dart'; 2 | import 'package:developine_app/core/bloc/network_state.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | import '../cubit/login_cubit.dart'; 6 | 7 | class LoginPage extends StatefulWidget { 8 | @override 9 | _LoginPageState createState() => _LoginPageState(); 10 | } 11 | 12 | class _LoginPageState extends State { 13 | final GlobalKey _scaffoldKey = new GlobalKey(); 14 | 15 | TextEditingController _emailController = new TextEditingController(); 16 | 17 | TextEditingController _passwordController = new TextEditingController(); 18 | 19 | TextEditingController _nameController = new TextEditingController(); 20 | 21 | late String _email; 22 | 23 | late String _password; 24 | 25 | late String _displayName; 26 | 27 | bool _obscure = false; 28 | late ThemeMode _themeMode; 29 | 30 | @override 31 | void initState() { 32 | super.initState(); 33 | } 34 | 35 | @override 36 | Widget build(BuildContext context) { 37 | return Scaffold( 38 | resizeToAvoidBottomInset: false, 39 | key: _scaffoldKey, 40 | backgroundColor: Theme.of(context).primaryColor, 41 | body: MultiBlocListener( 42 | listeners: [ 43 | BlocListener( 44 | listener: (context, state) { 45 | var snackBar = SnackBar( 46 | content: Text( 47 | state.message, 48 | style: TextStyle(color: Colors.white), 49 | ), 50 | ); 51 | // ScaffoldMessenger.of(context).showSnackBar(snackBar); 52 | }, 53 | ), 54 | ], 55 | child: BlocConsumer( 56 | listener: (oldState, newState) {}, 57 | builder: (BuildContext context, state) { 58 | return Center(); 59 | }, 60 | ), 61 | ), 62 | ); 63 | } 64 | 65 | void _loginUser() { 66 | _email = _emailController.text; 67 | _password = _passwordController.text; 68 | _emailController.clear(); 69 | _passwordController.clear(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/features/login/presentation/widgets/input_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | Widget inputWidget(Icon icon, String hint, TextEditingController controller, 4 | bool obscure, BuildContext context) { 5 | return Container( 6 | padding: EdgeInsets.only(left: 20, right: 20), 7 | child: TextField( 8 | controller: controller, 9 | obscureText: obscure, 10 | style: TextStyle( 11 | fontSize: 20, 12 | ), 13 | decoration: InputDecoration( 14 | hintStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 20), 15 | hintText: hint, 16 | enabledBorder: OutlineInputBorder( 17 | borderRadius: BorderRadius.circular(30), 18 | borderSide: BorderSide( 19 | color: Theme.of(context).primaryColor, 20 | width: 2, 21 | ), 22 | ), 23 | border: OutlineInputBorder( 24 | borderRadius: BorderRadius.circular(30), 25 | borderSide: BorderSide( 26 | color: Theme.of(context).primaryColor, 27 | width: 3, 28 | ), 29 | ), 30 | prefixIcon: Padding( 31 | child: IconTheme( 32 | data: IconThemeData(color: Theme.of(context).primaryColor), 33 | child: icon, 34 | ), 35 | padding: EdgeInsets.only(left: 30, right: 10), 36 | )), 37 | ), 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /lib/features/login/presentation/widgets/login_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LoginButton extends StatelessWidget { 4 | final String text; 5 | final Color splashColor; 6 | final textColor; 7 | final highlightColor; 8 | final fillColor; 9 | 10 | const LoginButton( 11 | {required Key key, 12 | required this.text, 13 | @required this.textColor, 14 | required this.splashColor, 15 | @required this.fillColor, 16 | @required this.highlightColor}) 17 | : super(key: key); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return RaisedButton( 22 | highlightElevation: 0.0, 23 | splashColor: splashColor, 24 | highlightColor: highlightColor, 25 | elevation: 0.0, 26 | color: fillColor, 27 | shape: 28 | RoundedRectangleBorder(borderRadius: new BorderRadius.circular(30.0)), 29 | child: Text( 30 | text, 31 | style: TextStyle( 32 | fontWeight: FontWeight.bold, color: textColor, fontSize: 20), 33 | ), 34 | onPressed: () {}, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/features/notifiations/domain/repositories/notifications_repo.dart: -------------------------------------------------------------------------------- 1 | abstract class NotificationsRepository {} -------------------------------------------------------------------------------- /lib/features/notifiations/presentation/manager/notifications_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | 6 | part 'notifications_event.dart'; 7 | part 'notifications_state.dart'; 8 | 9 | class NotificationsBloc extends Bloc { 10 | NotificationsBloc() : super(NotificationsInitial()) { 11 | on((event, emit) { 12 | // TODO: implement event handler 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/notifiations/presentation/manager/notifications_event.dart: -------------------------------------------------------------------------------- 1 | part of 'notifications_bloc.dart'; 2 | 3 | abstract class NotificationsEvent extends Equatable { 4 | const NotificationsEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/notifiations/presentation/manager/notifications_state.dart: -------------------------------------------------------------------------------- 1 | part of 'notifications_bloc.dart'; 2 | 3 | abstract class NotificationsState extends Equatable { 4 | const NotificationsState(); 5 | } 6 | 7 | class NotificationsInitial extends NotificationsState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/notifiations/presentation/pages/notifications_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CategoriesPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return CategoriesPageState(); 7 | } 8 | } 9 | 10 | class CategoriesPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | // TODO: implement build 19 | throw UnimplementedError(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/password/data/data_sources/password_remote_datasource.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/password/data/data_sources/password_remote_datasource.dart -------------------------------------------------------------------------------- /lib/features/password/data/models/password_model.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/password/data/models/password_model.dart -------------------------------------------------------------------------------- /lib/features/password/data/repositories/password_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/password_repo.dart'; 2 | 3 | class PasswordRepoImpl implements PasswordRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/password/domain/repositories/password_repo.dart: -------------------------------------------------------------------------------- 1 | abstract class PasswordRepository {} -------------------------------------------------------------------------------- /lib/features/password/presentation/manager/password_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | 6 | part 'password_event.dart'; 7 | part 'password_state.dart'; 8 | 9 | class PasswordBloc extends Bloc { 10 | PasswordBloc() : super(PasswordInitial()) { 11 | on((event, emit) { 12 | // TODO: implement event handler 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/password/presentation/manager/password_event.dart: -------------------------------------------------------------------------------- 1 | part of 'password_bloc.dart'; 2 | 3 | abstract class PasswordEvent extends Equatable { 4 | const PasswordEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/password/presentation/manager/password_state.dart: -------------------------------------------------------------------------------- 1 | part of 'password_bloc.dart'; 2 | 3 | abstract class PasswordState extends Equatable { 4 | const PasswordState(); 5 | } 6 | 7 | class PasswordInitial extends PasswordState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/password/presentation/pages/changepassword_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ChangePasswordPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | throw UnimplementedError(); 7 | } 8 | } 9 | 10 | class ChangePasswordPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | throw UnimplementedError(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/password/presentation/pages/forgotpassword_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ForgotPasswordPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return ForgotPasswordPageState(); 7 | } 8 | } 9 | 10 | class ForgotPasswordPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | throw UnimplementedError(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/payment/presentation/manager/payment_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | 6 | part 'payment_event.dart'; 7 | part 'payment_state.dart'; 8 | 9 | class PaymentBloc extends Bloc { 10 | PaymentBloc() : super(PaymentInitial()) { 11 | on((event, emit) { 12 | // TODO: implement event handler 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/payment/presentation/manager/payment_event.dart: -------------------------------------------------------------------------------- 1 | part of 'payment_bloc.dart'; 2 | 3 | abstract class PaymentEvent extends Equatable { 4 | const PaymentEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/payment/presentation/manager/payment_state.dart: -------------------------------------------------------------------------------- 1 | part of 'payment_bloc.dart'; 2 | 3 | abstract class PaymentState extends Equatable { 4 | const PaymentState(); 5 | } 6 | 7 | class PaymentInitial extends PaymentState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/profile/data/data_sources/profile_remote_datasource.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/profile/data/data_sources/profile_remote_datasource.dart -------------------------------------------------------------------------------- /lib/features/profile/data/models/profile_model.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/profile/data/models/profile_model.dart -------------------------------------------------------------------------------- /lib/features/profile/data/repositories/profile_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/profile_repo.dart'; 2 | 3 | class ProfileRepoImpl implements ProfileRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/profile/domain/repositories/profile_repo.dart: -------------------------------------------------------------------------------- 1 | abstract class ProfileRepository {} -------------------------------------------------------------------------------- /lib/features/profile/presentation/manager/profile_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | 6 | part 'profile_event.dart'; 7 | part 'profile_state.dart'; 8 | 9 | class ProfileBloc extends Bloc { 10 | ProfileBloc() : super(ProfileInitial()) { 11 | on((event, emit) { 12 | // TODO: implement event handler 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/manager/profile_event.dart: -------------------------------------------------------------------------------- 1 | part of 'profile_bloc.dart'; 2 | 3 | abstract class ProfileEvent extends Equatable { 4 | const ProfileEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/manager/profile_state.dart: -------------------------------------------------------------------------------- 1 | part of 'profile_bloc.dart'; 2 | 3 | abstract class ProfileState extends Equatable { 4 | const ProfileState(); 5 | } 6 | 7 | class ProfileInitial extends ProfileState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/pages/profile_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ProfilePage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return ProfilePageState(); 7 | } 8 | } 9 | 10 | class ProfilePageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | void dispose() { 18 | super.dispose(); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | // TODO: implement build 24 | throw UnimplementedError(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/search/data/data_sources/search_remote_datasource.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/search/data/data_sources/search_remote_datasource.dart -------------------------------------------------------------------------------- /lib/features/search/data/models/search_model.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/search/data/models/search_model.dart -------------------------------------------------------------------------------- /lib/features/search/data/repositories/search_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/search_repo.dart'; 2 | 3 | class SearchRepoImpl implements SearchRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/search/domain/repositories/search_repo.dart: -------------------------------------------------------------------------------- 1 | abstract class SearchRepository {} -------------------------------------------------------------------------------- /lib/features/search/presentation/manager/search_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | 6 | part 'search_event.dart'; 7 | part 'search_state.dart'; 8 | 9 | class SearchBloc extends Bloc { 10 | SearchBloc() : super(SearchInitial()) { 11 | on((event, emit) { 12 | // TODO: implement event handler 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/search/presentation/manager/search_event.dart: -------------------------------------------------------------------------------- 1 | part of 'search_bloc.dart'; 2 | 3 | abstract class SearchEvent extends Equatable { 4 | const SearchEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/search/presentation/manager/search_state.dart: -------------------------------------------------------------------------------- 1 | part of 'search_bloc.dart'; 2 | 3 | abstract class SearchState extends Equatable { 4 | const SearchState(); 5 | } 6 | 7 | class SearchInitial extends SearchState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/search/presentation/pages/search_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:developine_app/core/util/theme.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class SearchPage extends StatefulWidget { 5 | @override 6 | State createState() { 7 | return SearchPageState(); 8 | } 9 | } 10 | 11 | class SearchPageState extends State { 12 | @override 13 | void initState() { 14 | super.initState(); 15 | } 16 | 17 | @override 18 | void dispose() { 19 | super.dispose(); 20 | } 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Scaffold( 25 | body: Center( 26 | child: Text( 27 | 'This is search page', 28 | style: headline2, 29 | ), 30 | ), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/features/signup/data/data_sources/signup_remote_datasource.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/signup/data/data_sources/signup_remote_datasource.dart -------------------------------------------------------------------------------- /lib/features/signup/data/models/signup_model.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/signup/data/models/signup_model.dart -------------------------------------------------------------------------------- /lib/features/signup/data/repositories/signup_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/signup_repo.dart'; 2 | 3 | class SignUpRepoImpl implements SignupRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/signup/domain/repositories/signup_repo.dart: -------------------------------------------------------------------------------- 1 | abstract class SignupRepository {} -------------------------------------------------------------------------------- /lib/features/signup/presentation/manager/signup_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:meta/meta.dart'; 5 | 6 | part 'signup_event.dart'; 7 | part 'signup_state.dart'; 8 | 9 | class SignupBloc extends Bloc { 10 | SignupBloc() : super(SignupInitial()) { 11 | on((event, emit) { 12 | // TODO: implement event handler 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/signup/presentation/manager/signup_event.dart: -------------------------------------------------------------------------------- 1 | part of 'signup_bloc.dart'; 2 | 3 | @immutable 4 | abstract class SignupEvent {} 5 | -------------------------------------------------------------------------------- /lib/features/signup/presentation/manager/signup_state.dart: -------------------------------------------------------------------------------- 1 | part of 'signup_bloc.dart'; 2 | 3 | @immutable 4 | abstract class SignupState {} 5 | 6 | class SignupInitial extends SignupState {} 7 | -------------------------------------------------------------------------------- /lib/features/signup/presentation/pages/signup_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SignupPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return SignupPageState(); 7 | } 8 | } 9 | 10 | class SignupPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | void dispose() { 18 | super.dispose(); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | throw UnimplementedError(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/splash/splash_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:developer'; 3 | import 'package:developine_app/core/bloc/network_cubit.dart'; 4 | import 'package:developine_app/core/bloc/network_state.dart'; 5 | import 'package:developine_app/core/layout/colored_safearea.dart'; 6 | import 'package:developine_app/core/util/theme.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_bloc/flutter_bloc.dart'; 9 | import '../../core/const/route_constants.dart'; 10 | import '../../core/routing/routes.dart'; 11 | 12 | class SplashPage extends StatefulWidget { 13 | @override 14 | State createState() { 15 | return SplashPageState(); 16 | } 17 | } 18 | 19 | class SplashPageState extends State { 20 | @override 21 | void initState() { 22 | super.initState(); 23 | Timer( 24 | Duration(seconds: 5), 25 | () => RouteNavigator.pushRepalcementNamed( 26 | routeName: RoutesList.homeRoute)); 27 | } 28 | 29 | @override 30 | void dispose() { 31 | super.dispose(); 32 | } 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return ColoredSafeArea( 37 | color: backgroundColor, 38 | showBanner: false, 39 | child: Scaffold( 40 | backgroundColor: backgroundColor, 41 | body: BlocConsumer( 42 | builder: (BuildContext context, state) { 43 | return Column( 44 | mainAxisAlignment: MainAxisAlignment.center, 45 | crossAxisAlignment: CrossAxisAlignment.center, 46 | children: [ 47 | Expanded( 48 | child: Icon( 49 | Icons.download_for_offline_outlined, 50 | size: kIconL, 51 | ), 52 | ), 53 | Align( 54 | alignment: Alignment.center, 55 | child: CircularProgressIndicator(), 56 | ), 57 | SizedBox( 58 | height: kSpaceM, 59 | ), 60 | Visibility( 61 | visible: state is NetworkDisConnectedState, 62 | child: Text( 63 | state.message, 64 | style: subTitle2, 65 | textAlign: TextAlign.center, 66 | ), 67 | ), 68 | const SizedBox( 69 | height: kSpaceL, 70 | ) 71 | ], 72 | ); 73 | }, listener: (context, state) { 74 | if (state is NetworkInitialState || state is NetworkConnectedState) 75 | return; 76 | var snackBar = SnackBar( 77 | content: Text( 78 | state.message, 79 | style: subTitle2.copyWith(color: onPrimaryColor), 80 | ), 81 | ); 82 | ScaffoldMessenger.of(context).showSnackBar(snackBar); 83 | log("SplashPageState listener: ${state.message}"); 84 | }), 85 | ), 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /lib/features/support/data/data_sources/support_remote_datasource.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/support/data/data_sources/support_remote_datasource.dart -------------------------------------------------------------------------------- /lib/features/support/data/models/support_model.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/lib/features/support/data/models/support_model.dart -------------------------------------------------------------------------------- /lib/features/support/data/repositories/support_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import '../../domain/repositories/support_repo.dart'; 2 | 3 | class SupportRepoImpl implements SupportRepository {} 4 | -------------------------------------------------------------------------------- /lib/features/support/domain/repositories/support_repo.dart: -------------------------------------------------------------------------------- 1 | abstract class SupportRepository {} -------------------------------------------------------------------------------- /lib/features/support/presentation/manager/support_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | 6 | part 'support_event.dart'; 7 | part 'support_state.dart'; 8 | 9 | class SupportBloc extends Bloc { 10 | SupportBloc() : super(SupportInitial()) { 11 | on((event, emit) { 12 | // TODO: implement event handler 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/support/presentation/manager/support_event.dart: -------------------------------------------------------------------------------- 1 | part of 'support_bloc.dart'; 2 | 3 | abstract class SupportEvent extends Equatable { 4 | const SupportEvent(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/features/support/presentation/manager/support_state.dart: -------------------------------------------------------------------------------- 1 | part of 'support_bloc.dart'; 2 | 3 | abstract class SupportState extends Equatable { 4 | const SupportState(); 5 | } 6 | 7 | class SupportInitial extends SupportState { 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/support/presentation/pages/feeback_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FeedbackPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return FeedbackPageState(); 7 | } 8 | } 9 | 10 | class FeedbackPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | void dispose() { 18 | super.dispose(); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | // TODO: implement build 24 | throw UnimplementedError(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/support/presentation/pages/support_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SupportPage extends StatefulWidget { 4 | @override 5 | State createState() { 6 | return SupportPageState(); 7 | } 8 | } 9 | 10 | class SupportPageState extends State { 11 | @override 12 | void initState() { 13 | super.initState(); 14 | } 15 | 16 | @override 17 | void dispose() { 18 | super.dispose(); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | throw UnimplementedError(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/generated_plugin_registrant.dart: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // ignore_for_file: directives_ordering 6 | // ignore_for_file: lines_longer_than_80_chars 7 | // ignore_for_file: depend_on_referenced_packages 8 | 9 | import 'package:firebase_analytics_web/firebase_analytics_web.dart'; 10 | import 'package:firebase_core_web/firebase_core_web.dart'; 11 | import 'package:firebase_messaging_web/firebase_messaging_web.dart'; 12 | import 'package:location_web/location_web.dart'; 13 | import 'package:package_info_plus_web/package_info_plus_web.dart'; 14 | import 'package:shared_preferences_web/shared_preferences_web.dart'; 15 | import 'package:wakelock_web/wakelock_web.dart'; 16 | 17 | import 'package:flutter_web_plugins/flutter_web_plugins.dart'; 18 | 19 | // ignore: public_member_api_docs 20 | void registerPlugins(Registrar registrar) { 21 | FirebaseAnalyticsWeb.registerWith(registrar); 22 | FirebaseCoreWeb.registerWith(registrar); 23 | FirebaseMessagingWeb.registerWith(registrar); 24 | LocationWebPlugin.registerWith(registrar); 25 | PackageInfoPlugin.registerWith(registrar); 26 | SharedPreferencesPlugin.registerWith(registrar); 27 | WakelockWeb.registerWith(registrar); 28 | registrar.registerMessageHandler(); 29 | } 30 | -------------------------------------------------------------------------------- /lib/l10n/app_ar.arb: -------------------------------------------------------------------------------- 1 | { 2 | "helloWorld": "!مرحبا بالعالم", 3 | "@helloWorld": { 4 | "description": "The conventional newborn programmer greeting" 5 | } 6 | } -------------------------------------------------------------------------------- /lib/l10n/app_en.arb: -------------------------------------------------------------------------------- 1 | { 2 | "helloWorld": "Hello World", 3 | "@helloWorld": { 4 | "description": "The conventional newborn programmer greeting" 5 | } 6 | } -------------------------------------------------------------------------------- /lib/main_dev.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:developer'; 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'app.dart'; 6 | import 'config/env_config.dart'; 7 | import 'core/bloc/bloc_observer.dart'; 8 | import 'core/di/injection_container.dart'; 9 | import 'config/flavors.dart'; 10 | import 'core/firebase/firebase_notification_handler.dart'; 11 | 12 | void main() async { 13 | F.appFlavor = Flavor.dev; 14 | GlobalAppConfig( 15 | appName: "", 16 | flavorName: F.appFlavor.toString(), 17 | apiBaseURL: "http://restapi.adequateshop.com/api/authaccount"); 18 | FlutterError.onError = (details) { 19 | log(details.exceptionAsString(), stackTrace: details.stack); 20 | }; 21 | 22 | runZonedGuarded(() async { 23 | await BlocOverrides.runZoned( 24 | () async { 25 | WidgetsFlutterBinding.ensureInitialized(); 26 | initDI(); 27 | await initFirebaseApp(); 28 | FlutterError.onError = (FlutterErrorDetails details) { 29 | FlutterError.presentError(details); 30 | }; 31 | runApp( 32 | // testing repo link. 33 | App(), 34 | ); 35 | }, 36 | blocObserver: CubitObserver(), 37 | ); 38 | }, (error, stackTrace) { 39 | log("main_dev runZonedGuarded Error: $error"); 40 | log("main_dev runZonedGuarded StackTrace: $stackTrace"); 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /lib/main_prod.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:developer'; 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'app.dart'; 6 | import 'app_parent_view.dart'; 7 | import 'core/bloc/bloc_observer.dart'; 8 | import 'core/di/injection_container.dart'; 9 | import 'config/flavors.dart'; 10 | import 'core/firebase/firebase_notification_handler.dart'; 11 | 12 | void main() async { 13 | F.appFlavor = Flavor.prod; 14 | FlutterError.onError = (details) { 15 | log(details.exceptionAsString(), stackTrace: details.stack); 16 | }; 17 | 18 | runZonedGuarded(() async { 19 | await BlocOverrides.runZoned( 20 | () async { 21 | initDI(); 22 | WidgetsFlutterBinding.ensureInitialized(); 23 | await initFirebaseApp(); 24 | FlutterError.onError = (FlutterErrorDetails details) { 25 | FlutterError.presentError(details); 26 | }; 27 | runApp( 28 | App(), 29 | ); 30 | }, 31 | blocObserver: CubitObserver(), 32 | ); 33 | }, (error, stackTrace) { 34 | log("main_prod runZonedGuarded Error: $error"); 35 | log("main_prod runZonedGuarded StackTrace: $stackTrace"); 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /local.properties: -------------------------------------------------------------------------------- 1 | ## This file must *NOT* be checked into Version Control Systems, 2 | # as it contains information specific to your local configuration. 3 | # 4 | # Location of the SDK. This is only used by Gradle. 5 | # For customization when using a Version Control System, please read the 6 | # header note. 7 | #Wed Jan 20 16:39:34 GST 2021 8 | sdk.dir=/Users/Hammad.Tariq/Library/Android/sdk 9 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: developine_app 2 | description: Flutter demo application. 3 | 4 | version: 1.0.0+1 5 | 6 | environment: 7 | sdk: ">=2.16.2 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | # Bloc for state management 14 | flutter_bloc: ^8.0.1 15 | # font awesome library. 16 | font_awesome_flutter: ^10.1.0 17 | # Value equality 18 | equatable: ^2.0.3 19 | # Service locator 20 | get_it: ^7.2.0 21 | # For Navigation and Themes. 22 | get: ^4.6.5 23 | 24 | # Functional programming in Dart. 25 | dartz: ^0.10.1 26 | 27 | # Local cache 28 | shared_preferences: ^2.0.15 29 | 30 | # Localization 31 | flutter_localizations: 32 | sdk: flutter 33 | # To add localized text. 34 | intl: ^0.17.0 35 | 36 | # Networking 37 | dio: ^4.0.6 38 | simple_connection_checker: ^0.2.1 39 | 40 | 41 | path: ^1.8.0 42 | path_provider: ^2.0.0 43 | drift: ^1.5.0 44 | sqlite3_flutter_libs: ^0.5.7 45 | 46 | # HTTP inspector tool. 47 | alice: ^0.2.5 48 | 49 | firebase_messaging: ^11.4.0 50 | firebase_crashlytics: ^2.8.0 51 | firebase_analytics: ^9.1.8 52 | firebase_core: ^1.17.0 53 | flutter_local_notifications: ^9.5.3+1 54 | flutter_flavorizr: ^2.1.3 55 | permission_handler: ^8.3.0 56 | location: ^4.2.0 57 | 58 | google_fonts: ^3.0.1 59 | 60 | 61 | 62 | dev_dependencies: 63 | flutter_test: 64 | sdk: flutter 65 | mockito: ^5.2.0 66 | flutter_lints: ^2.0.1 67 | 68 | 69 | # The following section is specific to Flutter. 70 | flutter: 71 | # The following line ensures that the Material Icons font is 72 | # included with your application, so that you can use the icons in 73 | # the material Icons class. 74 | 75 | uses-material-design: true 76 | generate: true 77 | 78 | -------------------------------------------------------------------------------- /test/features/listing/data/repositories/user_list_repository_impl_test.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/features/listing/domain/usecases/get_user_list_test.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/features/listing/presentation/bloc/listing_bloc_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | void main() { 4 | setUp() {} 5 | } 6 | -------------------------------------------------------------------------------- /test/features/login/presentation/bloc/login_bloc_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | void main() { 4 | setUp() {} 5 | } 6 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:developine_app/app.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:flutter_test/flutter_test.dart'; 11 | 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(App()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hammad-tariq/flutter-app-architecture/6edbf1b783aafedd2e6cbbcab887f0fd358a6b11/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | demo_code 27 | 28 | 29 | 30 | 33 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo_code", 3 | "short_name": "demo_code", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | --------------------------------------------------------------------------------