├── .gitignore ├── .metadata ├── .vscode └── launch.json ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ ├── google-services.json │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── e_commerce_app │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── layout │ │ │ └── toast_custom.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── fonts │ ├── inter │ │ ├── Inter-Bold.ttf │ │ ├── Inter-ExtraBold.ttf │ │ ├── Inter-Medium.ttf │ │ └── Inter-Regular.ttf │ ├── open_sans │ │ ├── OpenSans-Bold.ttf │ │ ├── OpenSans-ExtraBold.ttf │ │ ├── OpenSans-Regular.ttf │ │ └── OpenSans-SemiBold.ttf │ ├── poppins │ │ ├── Poppins-Medium.otf │ │ ├── Poppins-Regular.otf │ │ └── Poppins-SemiBold.otf │ └── roboto │ │ ├── Roboto-Bold.ttf │ │ ├── Roboto-Medium.ttf │ │ └── Roboto-Regular.ttf ├── icons │ ├── Back ICon.svg │ ├── Bell.svg │ ├── Bill Icon.svg │ ├── Call.svg │ ├── Camera Icon.svg │ ├── Cart Icon.svg │ ├── Cash.svg │ ├── Chat bubble Icon.svg │ ├── Check mark rounde.svg │ ├── Close.svg │ ├── Conversation.svg │ ├── Discover.svg │ ├── Error.svg │ ├── Flash Icon.svg │ ├── Game Icon.svg │ ├── Gift Icon.svg │ ├── Heart Icon.svg │ ├── Heart Icon_2.svg │ ├── Location point.svg │ ├── Lock.svg │ ├── Log out.svg │ ├── Mail.svg │ ├── Parcel.svg │ ├── Phone.svg │ ├── Plus Icon.svg │ ├── Question mark.svg │ ├── Search Icon.svg │ ├── Settings.svg │ ├── Shop Icon.svg │ ├── Star Icon.svg │ ├── Success.svg │ ├── Trash.svg │ ├── User Icon.svg │ ├── User.svg │ ├── add-to-basket.svg │ ├── add.svg │ ├── all.svg │ ├── arrow_right.svg │ ├── cancel.svg │ ├── controls.svg │ ├── display.svg │ ├── edit-button.svg │ ├── exit.svg │ ├── facebook-2.svg │ ├── free-delivery.svg │ ├── google-icon.svg │ ├── headphones.svg │ ├── home.svg │ ├── ic_facebook.svg │ ├── ic_google.svg │ ├── keyboard.svg │ ├── keyboard_1.svg │ ├── keyboard_ver2.svg │ ├── location.svg │ ├── logo.svg │ ├── menu.svg │ ├── message.svg │ ├── mouse.svg │ ├── multi_users.svg │ ├── order.svg │ ├── peach.svg │ ├── receipt.svg │ ├── remove-from-cart.svg │ ├── remove.svg │ ├── return-free.svg │ ├── safety.svg │ ├── screen.svg │ ├── shipped.svg │ ├── shipping.svg │ ├── shopping-bag.svg │ ├── sort.svg │ ├── speech.svg │ ├── subtract.svg │ ├── twitter.svg │ └── video-camera.svg ├── images │ ├── Not Found.png │ ├── Pattern Success.png │ ├── add_address.jpg │ ├── add_address.png │ ├── apple-pay.png │ ├── default_avatar.jpg │ ├── empty_cart.png │ ├── fedex-express.png │ ├── google-pay.png │ ├── headphone.png │ ├── ic_launcher.png │ ├── keyboard.jpg │ ├── mastercard-2.png │ ├── mouse.png │ ├── no_record.png │ ├── paypal.png │ ├── sale_banner1.jpg │ ├── sale_banner2.jpg │ ├── sale_banner3.jpg │ ├── screen.png │ ├── splash_1.png │ ├── success.png │ ├── success_gif.gif │ └── visa.png └── locale │ ├── en.json │ └── vi.json ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── 1024.png │ │ ├── 114.png │ │ ├── 120.png │ │ ├── 180.png │ │ ├── 29.png │ │ ├── 40.png │ │ ├── 57.png │ │ ├── 58.png │ │ ├── 60.png │ │ ├── 80.png │ │ ├── 87.png │ │ └── Contents.json │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── app_locale_delegate.dart ├── app_view.dart ├── bottom_navigation.dart ├── configs │ ├── application.dart │ ├── config.dart │ ├── language.dart │ ├── router.dart │ ├── size_config.dart │ └── theme.dart ├── constants │ ├── color_constant.dart │ ├── constants.dart │ ├── font_constant.dart │ ├── icon_constant.dart │ ├── image_constant.dart │ └── key_constant.dart ├── data │ ├── local │ │ └── pref.dart │ ├── models │ │ ├── banner_model.dart │ │ ├── cart_item_model.dart │ │ ├── category_model.dart │ │ ├── delivery_address_model.dart │ │ ├── error_model.dart │ │ ├── feedback_model.dart │ │ ├── location_model.dart │ │ ├── message_model.dart │ │ ├── models.dart │ │ ├── order_model.dart │ │ ├── product_model.dart │ │ └── user_model.dart │ ├── repository │ │ ├── app_repository.dart │ │ ├── auth_repository │ │ │ ├── auth_repo.dart │ │ │ └── firebase_auth_repo.dart │ │ ├── banner_repository │ │ │ ├── banner_repo.dart │ │ │ └── firebase_banner_repo.dart │ │ ├── cart_repository │ │ │ ├── cart_repo.dart │ │ │ └── firebase_cart_repo.dart │ │ ├── feedback_repository │ │ │ ├── feedback_repo.dart │ │ │ └── firebase_feedback_repo.dart │ │ ├── location_repository │ │ │ └── location_repo.dart │ │ ├── message_repository │ │ │ ├── firebase_message_repo.dart │ │ │ └── message_repo.dart │ │ ├── order_repository │ │ │ ├── firebase_order_repo.dart │ │ │ └── order_repo.dart │ │ ├── product_repository │ │ │ ├── firebase_product_repo.dart │ │ │ └── product_repo.dart │ │ ├── repository.dart │ │ ├── storage_repository │ │ │ └── storage_repo.dart │ │ └── user_repository │ │ │ ├── firebase_user_repo.dart │ │ │ └── user_repo.dart │ └── request │ │ ├── api_url.dart │ │ └── request.dart ├── main.dart ├── presentation │ ├── common_blocs │ │ ├── application │ │ │ ├── application_bloc.dart │ │ │ ├── application_event.dart │ │ │ ├── application_state.dart │ │ │ └── bloc.dart │ │ ├── auth │ │ │ ├── auth_bloc.dart │ │ │ ├── auth_event.dart │ │ │ ├── auth_state.dart │ │ │ └── bloc.dart │ │ ├── cart │ │ │ ├── bloc.dart │ │ │ ├── cart_bloc.dart │ │ │ ├── cart_event.dart │ │ │ └── cart_state.dart │ │ ├── common_bloc.dart │ │ ├── language │ │ │ ├── bloc.dart │ │ │ ├── language_bloc.dart │ │ │ ├── language_event.dart │ │ │ └── language_state.dart │ │ ├── order │ │ │ ├── bloc.dart │ │ │ ├── order_bloc.dart │ │ │ ├── order_event.dart │ │ │ └── order_state.dart │ │ ├── profile │ │ │ ├── bloc.dart │ │ │ ├── profile_bloc.dart │ │ │ ├── profile_event.dart │ │ │ └── profile_state.dart │ │ └── simple_bloc_observer.dart │ ├── screens │ │ ├── cart │ │ │ ├── cart_screen.dart │ │ │ └── widgets │ │ │ │ ├── checkout_bottom.dart │ │ │ │ ├── list_cart_item.dart │ │ │ │ └── payment_bottom_sheet.dart │ │ ├── categories │ │ │ ├── bloc │ │ │ │ ├── bloc.dart │ │ │ │ ├── categories_bloc.dart │ │ │ │ ├── categories_event.dart │ │ │ │ └── categories_state.dart │ │ │ ├── categories_screen.dart │ │ │ └── widgets │ │ │ │ ├── grid_products.dart │ │ │ │ ├── product_gallery.dart │ │ │ │ ├── sort_option_dialog.dart │ │ │ │ └── toolbar.dart │ │ ├── delivery_address │ │ │ ├── address_picker │ │ │ │ ├── address_picker.dart │ │ │ │ └── bloc │ │ │ │ │ ├── address_picker_bloc.dart │ │ │ │ │ ├── address_picker_event.dart │ │ │ │ │ ├── address_picker_state.dart │ │ │ │ │ └── bloc.dart │ │ │ ├── delivery_address_bottom_sheet.dart │ │ │ └── delivery_address_screen.dart │ │ ├── detail_image │ │ │ └── detail_image_screen.dart │ │ ├── detail_order │ │ │ └── detail_order_screen.dart │ │ ├── detail_product │ │ │ ├── detail_product_screen.dart │ │ │ └── widgets │ │ │ │ ├── add_to_cart_nav.dart │ │ │ │ ├── app_bar.dart │ │ │ │ ├── product_images.dart │ │ │ │ ├── product_info.dart │ │ │ │ ├── related_products │ │ │ │ ├── bloc │ │ │ │ │ ├── bloc.dart │ │ │ │ │ ├── related_products_bloc.dart │ │ │ │ │ ├── related_products_event.dart │ │ │ │ │ └── related_products_state.dart │ │ │ │ └── related_products.dart │ │ │ │ └── slogan.dart │ │ ├── feedbacks │ │ │ ├── bloc │ │ │ │ ├── bloc.dart │ │ │ │ ├── feedback_bloc.dart │ │ │ │ ├── feedback_event.dart │ │ │ │ └── feedback_state.dart │ │ │ ├── feedbacks_screen.dart │ │ │ └── widgets │ │ │ │ ├── feedback_bottom_sheet.dart │ │ │ │ ├── header.dart │ │ │ │ └── list_feedbacks.dart │ │ ├── forgot_password │ │ │ ├── forgot_password_screen.dart │ │ │ └── widgets │ │ │ │ ├── body.dart │ │ │ │ └── forgot_pass_form.dart │ │ ├── home_page │ │ │ ├── bloc │ │ │ │ ├── bloc.dart │ │ │ │ ├── home_bloc.dart │ │ │ │ ├── home_event.dart │ │ │ │ └── home_state.dart │ │ │ ├── home_screen.dart │ │ │ └── widgets │ │ │ │ ├── home_banner.dart │ │ │ │ ├── home_body.dart │ │ │ │ └── home_header.dart │ │ ├── initialize_info │ │ │ ├── initialize_info_screen.dart │ │ │ └── widgets │ │ │ │ ├── initialize_info_form.dart │ │ │ │ └── initialize_info_header.dart │ │ ├── login │ │ │ ├── bloc │ │ │ │ ├── bloc.dart │ │ │ │ ├── login_bloc.dart │ │ │ │ ├── login_event.dart │ │ │ │ └── login_state.dart │ │ │ ├── login_screen.dart │ │ │ └── widgets │ │ │ │ ├── login_form.dart │ │ │ │ └── login_header.dart │ │ ├── map │ │ │ └── map_screen.dart │ │ ├── message │ │ │ ├── bloc │ │ │ │ ├── bloc.dart │ │ │ │ ├── message_bloc.dart │ │ │ │ ├── message_event.dart │ │ │ │ └── message_state.dart │ │ │ ├── message_screen.dart │ │ │ └── widgets │ │ │ │ ├── chat_input_field.dart │ │ │ │ ├── list_messages.dart │ │ │ │ └── message_card.dart │ │ ├── my_orders │ │ │ └── my_orders_screen.dart │ │ ├── profile │ │ │ ├── profile_header.dart │ │ │ └── profile_screen.dart │ │ ├── register │ │ │ ├── register │ │ │ │ ├── bloc.dart │ │ │ │ ├── register_bloc.dart │ │ │ │ ├── register_event.dart │ │ │ │ └── register_state.dart │ │ │ ├── register_screen.dart │ │ │ └── widgets │ │ │ │ ├── register_form.dart │ │ │ │ └── register_header.dart │ │ ├── search │ │ │ ├── bloc │ │ │ │ ├── bloc.dart │ │ │ │ ├── search_bloc.dart │ │ │ │ ├── search_event.dart │ │ │ │ └── search_state.dart │ │ │ ├── search_screen.dart │ │ │ └── widgets │ │ │ │ ├── search_bar.dart │ │ │ │ └── suggestion.dart │ │ ├── settings │ │ │ └── setting_screen.dart │ │ └── splash │ │ │ └── splash_screen.dart │ └── widgets │ │ ├── buttons │ │ ├── cart_button.dart │ │ ├── circle_icon_button.dart │ │ ├── default_button.dart │ │ ├── icon_button_with_counter.dart │ │ └── message_button.dart │ │ ├── custom_widgets.dart │ │ ├── others │ │ ├── custom_card_widget.dart │ │ ├── custom_dismissible.dart │ │ ├── custom_list_tile.dart │ │ ├── loading.dart │ │ ├── payment_fees_widget.dart │ │ ├── promo_widget.dart │ │ ├── rating_bar.dart │ │ ├── search_field_widget.dart │ │ ├── section_widget.dart │ │ ├── shimmer_image.dart │ │ └── text_row.dart │ │ └── single_card │ │ ├── cart_item_card.dart │ │ ├── category_card.dart │ │ ├── delivery_address_card.dart │ │ ├── feedback_card.dart │ │ ├── order_card.dart │ │ └── product_card.dart └── utils │ ├── app_extension.dart │ ├── dialog.dart │ ├── formatter.dart │ ├── language.dart │ ├── logger.dart │ ├── toast.dart │ ├── translate.dart │ ├── utils.dart │ └── validator.dart ├── pubspec.lock ├── pubspec.yaml └── screenshots ├── add_address.png ├── banner.png ├── cart.png ├── delivery_address.png ├── detail_product.png ├── empty_cart.png ├── feedback.png ├── filter.png ├── grid_products.png ├── home.png ├── language.png ├── list_product.png ├── login.png ├── message.png ├── no_product.png ├── payment.png ├── profile.png ├── screens.png ├── search.png └── splash.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | -------------------------------------------------------------------------------- /.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: 78910062997c3a836feee883712c241a5fd22983 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": "e_commerce_app", 9 | "request": "launch", 10 | "type": "dart" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "455084769239", 4 | "project_id": "e-commerce-flutter-526ce", 5 | "storage_bucket": "e-commerce-flutter-526ce.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:455084769239:android:36b7eb24d412501ec81592", 11 | "android_client_info": { 12 | "package_name": "com.example.e_commerce_app" 13 | } 14 | }, 15 | "oauth_client": [ 16 | { 17 | "client_id": "455084769239-h70maod998jr2a4fi224r9ahld832f4h.apps.googleusercontent.com", 18 | "client_type": 3 19 | } 20 | ], 21 | "api_key": [ 22 | { 23 | "current_key": "AIzaSyAyBppREvljm-E1aBeG13wnqVX8QvNbv5M" 24 | } 25 | ], 26 | "services": { 27 | "appinvite_service": { 28 | "other_platform_oauth_client": [ 29 | { 30 | "client_id": "455084769239-h70maod998jr2a4fi224r9ahld832f4h.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/main/kotlin/com/example/e_commerce_app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.e_commerce_app 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 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/toast_custom.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 23 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/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 | #3ac5c9 19 | 20 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | classpath 'com.google.gms:google-services:4.3.5' 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | google() 18 | jcenter() 19 | } 20 | } 21 | 22 | rootProject.buildDir = '../build' 23 | subprojects { 24 | project.buildDir = "${rootProject.buildDir}/${project.name}" 25 | } 26 | subprojects { 27 | project.evaluationDependsOn(':app') 28 | } 29 | 30 | task clean(type: Delete) { 31 | delete rootProject.buildDir 32 | } 33 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | android.enableR8=true 5 | -------------------------------------------------------------------------------- /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 | 13 | // def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 14 | 15 | // def plugins = new Properties() 16 | // def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 17 | // if (pluginsFile.exists()) { 18 | // pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 19 | // } 20 | 21 | // plugins.each { name, path -> 22 | // def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 23 | // include ":$name" 24 | // project(":$name").projectDir = pluginDirectory 25 | // } -------------------------------------------------------------------------------- /assets/fonts/inter/Inter-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/inter/Inter-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/inter/Inter-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/inter/Inter-ExtraBold.ttf -------------------------------------------------------------------------------- /assets/fonts/inter/Inter-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/inter/Inter-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/inter/Inter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/inter/Inter-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/open_sans/OpenSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/open_sans/OpenSans-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/open_sans/OpenSans-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/open_sans/OpenSans-ExtraBold.ttf -------------------------------------------------------------------------------- /assets/fonts/open_sans/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/open_sans/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/open_sans/OpenSans-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/open_sans/OpenSans-SemiBold.ttf -------------------------------------------------------------------------------- /assets/fonts/poppins/Poppins-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/poppins/Poppins-Medium.otf -------------------------------------------------------------------------------- /assets/fonts/poppins/Poppins-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/poppins/Poppins-Regular.otf -------------------------------------------------------------------------------- /assets/fonts/poppins/Poppins-SemiBold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/poppins/Poppins-SemiBold.otf -------------------------------------------------------------------------------- /assets/fonts/roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/fonts/roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /assets/icons/Back ICon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Bell.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Bill Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Call.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Camera Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Cart Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Cash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Chat bubble Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Check mark rounde.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Conversation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Discover.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Flash Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Gift Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Heart Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Heart Icon_2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Location point.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Lock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Log out.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Mail.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Parcel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Phone.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Plus Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Question mark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Search Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Star Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Success.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/Trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/User Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/User.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/add-to-basket.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/all.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/arrow_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/cancel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 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 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /assets/icons/controls.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /assets/icons/display.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/exit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/facebook-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/google-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/icons/home.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 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 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /assets/icons/ic_facebook.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /assets/icons/ic_google.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 11 | 14 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /assets/icons/location.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /assets/icons/menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /assets/icons/message.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/multi_users.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /assets/icons/receipt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/remove-from-cart.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/remove.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/return-free.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /assets/icons/safety.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/screen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/shopping-bag.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/sort.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /assets/icons/subtract.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/video-camera.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 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 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /assets/images/Not Found.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/Not Found.png -------------------------------------------------------------------------------- /assets/images/Pattern Success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/Pattern Success.png -------------------------------------------------------------------------------- /assets/images/add_address.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/add_address.jpg -------------------------------------------------------------------------------- /assets/images/add_address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/add_address.png -------------------------------------------------------------------------------- /assets/images/apple-pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/apple-pay.png -------------------------------------------------------------------------------- /assets/images/default_avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/default_avatar.jpg -------------------------------------------------------------------------------- /assets/images/empty_cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/empty_cart.png -------------------------------------------------------------------------------- /assets/images/fedex-express.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/fedex-express.png -------------------------------------------------------------------------------- /assets/images/google-pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/google-pay.png -------------------------------------------------------------------------------- /assets/images/headphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/headphone.png -------------------------------------------------------------------------------- /assets/images/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/ic_launcher.png -------------------------------------------------------------------------------- /assets/images/keyboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/keyboard.jpg -------------------------------------------------------------------------------- /assets/images/mastercard-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/mastercard-2.png -------------------------------------------------------------------------------- /assets/images/mouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/mouse.png -------------------------------------------------------------------------------- /assets/images/no_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/no_record.png -------------------------------------------------------------------------------- /assets/images/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/paypal.png -------------------------------------------------------------------------------- /assets/images/sale_banner1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/sale_banner1.jpg -------------------------------------------------------------------------------- /assets/images/sale_banner2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/sale_banner2.jpg -------------------------------------------------------------------------------- /assets/images/sale_banner3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/sale_banner3.jpg -------------------------------------------------------------------------------- /assets/images/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/screen.png -------------------------------------------------------------------------------- /assets/images/splash_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/splash_1.png -------------------------------------------------------------------------------- /assets/images/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/success.png -------------------------------------------------------------------------------- /assets/images/success_gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/success_gif.gif -------------------------------------------------------------------------------- /assets/images/visa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/assets/images/visa.png -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/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/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 "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | {"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"}]} -------------------------------------------------------------------------------- /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/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/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/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 | e_commerce_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" 2 | -------------------------------------------------------------------------------- /lib/app_locale_delegate.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/configs/config.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import 'utils/translate.dart'; 5 | 6 | class AppLocaleDelegate extends LocalizationsDelegate { 7 | const AppLocaleDelegate(); 8 | 9 | @override 10 | bool isSupported(Locale locale) { 11 | return AppLanguage.supportLanguage.contains(locale); 12 | } 13 | 14 | @override 15 | Future load(Locale locale) async { 16 | final localizations = Translate(locale); 17 | await localizations.load(); 18 | return localizations; 19 | } 20 | 21 | @override 22 | bool shouldReload(AppLocaleDelegate old) => false; 23 | } 24 | -------------------------------------------------------------------------------- /lib/configs/application.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | class Application { 4 | static bool debug = false; 5 | static String title = "E-commerce-app"; 6 | static late SharedPreferences preferences; 7 | 8 | Future setPreferences() async { 9 | preferences = await SharedPreferences.getInstance(); 10 | } 11 | 12 | /// Singleton factory 13 | static final Application _instance = Application._internal(); 14 | 15 | factory Application() { 16 | return _instance; 17 | } 18 | 19 | Application._internal(); 20 | } 21 | -------------------------------------------------------------------------------- /lib/configs/config.dart: -------------------------------------------------------------------------------- 1 | export 'language.dart'; 2 | export 'router.dart'; 3 | export 'size_config.dart'; 4 | export 'theme.dart'; 5 | export 'application.dart'; 6 | -------------------------------------------------------------------------------- /lib/configs/language.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppLanguage { 4 | /// Default Language 5 | static Locale defaultLanguage = Locale("en"); 6 | 7 | /// List language is supported in application 8 | static List supportLanguage = [ 9 | Locale("en"), 10 | Locale("vi"), 11 | ]; 12 | 13 | ///Singleton factory 14 | static final AppLanguage _instance = AppLanguage._internal(); 15 | 16 | factory AppLanguage() { 17 | return _instance; 18 | } 19 | 20 | AppLanguage._internal(); 21 | } 22 | -------------------------------------------------------------------------------- /lib/configs/size_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SizeConfig { 4 | static late double screenWidth; 5 | static late double screenHeight; 6 | static late double defaultSize; 7 | static Orientation? orientation; 8 | 9 | static double get defaultPadding => defaultSize * 1.5; 10 | 11 | void init(BoxConstraints constraints, Orientation orientation) { 12 | screenWidth = constraints.maxWidth; 13 | screenHeight = constraints.maxHeight; 14 | //Apple iPhone 11 viewport size is 414 x 896 (px) 15 | //With iPhone 11, i set defaultSize = 10; 16 | //So if the screen increase or decrease then our defaultSize also vary 17 | if (orientation == Orientation.portrait) { 18 | defaultSize = screenHeight * 10 / 896; 19 | } else { 20 | defaultSize = screenHeight * 10 / 414; 21 | } 22 | } 23 | 24 | ///Singleton factory 25 | static final SizeConfig _instance = SizeConfig._internal(); 26 | 27 | factory SizeConfig() { 28 | return _instance; 29 | } 30 | 31 | SizeConfig._internal(); 32 | } 33 | -------------------------------------------------------------------------------- /lib/constants/color_constant.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class COLOR_CONST { 4 | static const primaryColor = Color(0xFF3ac5c9); 5 | static const accentTintColor = Color(0xFF7b60c4); 6 | static const accentShadeColor = Color(0xFF58458c); 7 | static const darkShadeColor = Color(0xFF25164d); 8 | static const borderColor = Color(0xFFd3d1d1); 9 | static const backgroundColor = Color(0xffF6F7FB); 10 | static const cardShadowColor = Color(0xFFd3d1d1); 11 | static const dividerColor = Colors.black12; 12 | static const primaryGradientColor = LinearGradient( 13 | begin: Alignment.topCenter, 14 | end: Alignment.bottomCenter, 15 | colors: [Color(0xFF25164d), Colors.white], 16 | ); 17 | 18 | static const secondaryColor = Color(0xFF979797); 19 | static const textColor = Color(0xFF4a4a4a); 20 | static const googleButtonColor = Color(0xFFFFF1F0); 21 | static const deleteButtonColor = Color(0xFFeb4d4b); 22 | static const googleButtonColorBorder = Color(0xFFF14336); 23 | static const facebookButtonColor = Color(0xFFF5F9FF); 24 | static const facebookButtonColorBorder = Color(0xFF3164CE); 25 | static const discountColor = Color(0xFFF17322); 26 | 27 | ///Singleton factory 28 | static final COLOR_CONST _instance = COLOR_CONST._internal(); 29 | 30 | factory COLOR_CONST() { 31 | return _instance; 32 | } 33 | 34 | COLOR_CONST._internal(); 35 | } 36 | 37 | const mAnimationDuration = Duration(milliseconds: 200); 38 | -------------------------------------------------------------------------------- /lib/constants/constants.dart: -------------------------------------------------------------------------------- 1 | export 'color_constant.dart'; 2 | export 'font_constant.dart'; 3 | export 'image_constant.dart'; 4 | export 'icon_constant.dart'; -------------------------------------------------------------------------------- /lib/constants/icon_constant.dart: -------------------------------------------------------------------------------- 1 | class ICON_CONST { 2 | static const HOME = "assets/icons/home.svg"; 3 | static const MESSAGE = "assets/icons/speech.svg"; 4 | static const USER = "assets/icons/User Icon.svg"; 5 | static const SETTING = "assets/icons/Settings.svg"; 6 | static const CART = "assets/icons/shopping-bag.svg"; 7 | static const ADD_TO_CART = "assets/icons/add-to-basket.svg"; 8 | static const LOG_OUT = "assets/icons/exit.svg"; 9 | static const CAMERA = "assets/icons/Camera Icon.svg"; 10 | static const RECEIPT = "assets/icons/receipt.svg"; 11 | static const CANCEL = "assets/icons/cancel.svg"; 12 | static const CHECK_MARK = "assets/icons/Check mark rounde.svg"; 13 | static const SUBTRACT = "assets/icons/subtract.svg"; 14 | static const ADD = "assets/icons/add.svg"; 15 | static const ADDRESS = "assets/icons/location.svg"; 16 | static const ORDER = "assets/icons/order.svg"; 17 | } 18 | -------------------------------------------------------------------------------- /lib/constants/image_constant.dart: -------------------------------------------------------------------------------- 1 | class IMAGE_CONST { 2 | static const APP_LOGO = "assets/images/ic_launcher.png"; 3 | static const CART_EMPTY = "assets/images/empty_cart.png"; 4 | static const NOT_FOUND = "assets/images/Not Found.png"; 5 | static const NO_RECORD = "assets/images/no_record.png"; 6 | static const SUCCESS = "assets/images/success.png"; 7 | static const DEFAULT_AVATAR = "assets/images/default_avatar.jpg"; 8 | static const ADD_ADDRESS = "assets/images/add_address.jpg"; 9 | } 10 | -------------------------------------------------------------------------------- /lib/constants/key_constant.dart: -------------------------------------------------------------------------------- 1 | abstract class KEY_CONST { 2 | //error description 3 | static const request_send_timeout = "request_send_timeout"; 4 | static const request_cancelled = "request_cancelled"; 5 | static const request_connect_timeout = "request_connect_timeout"; 6 | static const no_internet = "no_internet"; 7 | static const request_receive_timeout = "request_receive_timeout"; 8 | static const not_found = "Not found."; 9 | static const error = "Error"; 10 | static const unknown_error = "Unknown_error"; 11 | } 12 | 13 | class MovieListType { 14 | static String popular = "popular"; 15 | static String nowPlaying = "now_playing"; 16 | static String topRated = "top_rated"; 17 | static String upcoming = "upcoming"; 18 | } 19 | -------------------------------------------------------------------------------- /lib/data/models/banner_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class BannerModel extends Equatable { 4 | final String id; 5 | final String imageUrl; 6 | 7 | BannerModel({required this.id, required this.imageUrl}); 8 | 9 | /// Json data from server turns into model data 10 | static BannerModel fromMap(Map data) { 11 | return BannerModel( 12 | id: data["id"] ?? "", 13 | imageUrl: data["imageUrl"] ?? "", 14 | ); 15 | } 16 | 17 | /// From model data turns into json data => server 18 | Map toMap() { 19 | return { 20 | "id": this.id, 21 | "name": this.imageUrl, 22 | }; 23 | } 24 | 25 | @override 26 | String toString() { 27 | return 'BannerModel{id: $id, url: $imageUrl}'; 28 | } 29 | 30 | @override 31 | List get props => [id, imageUrl]; 32 | } 33 | -------------------------------------------------------------------------------- /lib/data/models/cart_item_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | /// Cart item model 5 | class CartItemModel extends Equatable { 6 | /// Cart item id 7 | final String id; 8 | 9 | /// Product Id 10 | final String productId; 11 | 12 | /// Product quantity in the cart 13 | final int quantity; 14 | 15 | /// Product price * quantity 16 | final int price; 17 | 18 | /// Product info, only use in client side 19 | final Product? productInfo; 20 | 21 | /// Constructor 22 | CartItemModel({ 23 | required this.id, 24 | required this.productId, 25 | required this.price, 26 | required this.quantity, 27 | this.productInfo, 28 | }); 29 | 30 | /// Json data from server turns into model data 31 | static CartItemModel fromMap(Map data) { 32 | return CartItemModel( 33 | id: data["id"] ?? "", 34 | productId: data["productId"], 35 | price: data["price"], 36 | quantity: data["quantity"] ?? 0, 37 | ); 38 | } 39 | 40 | /// From model data turns into json data => server 41 | Map toMap() { 42 | return { 43 | "id": this.id, 44 | "productId": this.productId, 45 | "price": this.price, 46 | "quantity": this.quantity, 47 | }; 48 | } 49 | 50 | /// Clone and update 51 | CartItemModel cloneWith({ 52 | id, 53 | productId, 54 | productInfo, 55 | price, 56 | quantity, 57 | }) { 58 | return CartItemModel( 59 | id: id ?? this.id, 60 | productId: productId ?? this.productId, 61 | productInfo: productInfo ?? this.productInfo, 62 | price: price ?? this.price, 63 | quantity: quantity ?? this.quantity, 64 | ); 65 | } 66 | 67 | @override 68 | List get props => [id, quantity, price, productId]; 69 | } 70 | -------------------------------------------------------------------------------- /lib/data/models/category_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | /// CategoryModel model 4 | class CategoryModel extends Equatable { 5 | final String id; 6 | final String name; 7 | final String imageUrl; 8 | 9 | const CategoryModel({ 10 | required this.id, 11 | required this.name, 12 | required this.imageUrl, 13 | }); 14 | 15 | /// Json data from server turns into model data 16 | static CategoryModel fromMap(String id, Map data) { 17 | return CategoryModel( 18 | id: data["id"] ?? "", 19 | name: data["name"] ?? "", 20 | imageUrl: data["imageUrl"] ?? "", 21 | ); 22 | } 23 | 24 | /// From model data turns into json data => server 25 | Map toMap() { 26 | return { 27 | "id": this.id, 28 | "name": this.name, 29 | "imageUrl": this.imageUrl, 30 | }; 31 | } 32 | 33 | @override 34 | String toString() { 35 | return this.name; 36 | } 37 | 38 | @override 39 | List get props => [this.id]; 40 | } 41 | -------------------------------------------------------------------------------- /lib/data/models/error_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/constants/key_constant.dart'; 2 | 3 | class ErrorModel { 4 | int code; 5 | String description; 6 | String message; 7 | 8 | ErrorModel({ 9 | this.code = 0, 10 | this.message = KEY_CONST.error, 11 | this.description = KEY_CONST.unknown_error, 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /lib/data/models/location_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class LocationModel extends Equatable { 4 | final String id; 5 | final String name; 6 | 7 | LocationModel({this.id = "", this.name = ""}); 8 | 9 | static LocationModel fromMap(Map data) { 10 | return LocationModel( 11 | id: data["code"] ?? "", 12 | name: data["name"] ?? "", 13 | ); 14 | } 15 | 16 | Map toMap() { 17 | return { 18 | "code": this.id, 19 | "name": this.name, 20 | }; 21 | } 22 | 23 | @override 24 | List get props => [id, name]; 25 | } 26 | -------------------------------------------------------------------------------- /lib/data/models/models.dart: -------------------------------------------------------------------------------- 1 | export 'banner_model.dart'; 2 | export 'product_model.dart'; 3 | export 'user_model.dart'; 4 | export 'cart_item_model.dart'; 5 | export 'feedback_model.dart'; 6 | export 'category_model.dart'; 7 | export 'order_model.dart'; 8 | export 'delivery_address_model.dart'; 9 | export 'message_model.dart'; 10 | -------------------------------------------------------------------------------- /lib/data/repository/app_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/repository/location_repository/location_repo.dart'; 2 | import 'package:e_commerce_app/data/repository/repository.dart'; 3 | 4 | class AppRepository { 5 | /// Repository 6 | static final authRepository = FirebaseAuthRepository(); 7 | static final userRepository = FirebaseUserRepository(); 8 | static final productRepository = FirebaseProductRepository(); 9 | static final bannerRepository = FirebaseBannerRepository(); 10 | static final cartRepository = FirebaseCartRepository(); 11 | static final orderRepository = FirebaseOrderRepository(); 12 | static final feedbackRepository = FirebaseFeedbackRepository(); 13 | static final messageRepository = FirebaseMessageRepository(); 14 | static final storageRepository = StorageRepository(); 15 | static final locationRepository = LocationRepository(); 16 | 17 | /// Singleton factory 18 | static final AppRepository _instance = AppRepository._internal(); 19 | 20 | factory AppRepository() { 21 | return _instance; 22 | } 23 | AppRepository._internal(); 24 | } 25 | -------------------------------------------------------------------------------- /lib/data/repository/auth_repository/auth_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:firebase_auth/firebase_auth.dart'; 3 | 4 | abstract class AuthRepository { 5 | User get loggedFirebaseUser; 6 | String get authException; 7 | 8 | /// Creates a new user with the provided [information] 9 | /// Created by NDH 10 | Future signUp(UserModel newUser, String password); 11 | 12 | /// Signs in with the provided [email] and [password]. 13 | /// Created by NDH 14 | Future logInWithEmailAndPassword(String email, String password); 15 | 16 | /// Starts the Sign In with Google Flow. 17 | /// Created by NDH 18 | // Future logInWithGoogle(); 19 | 20 | bool isLoggedIn(); 21 | 22 | /// Signs out the current user 23 | /// Created by NDH 24 | Future logOut(); 25 | } 26 | -------------------------------------------------------------------------------- /lib/data/repository/banner_repository/banner_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | 3 | abstract class BannerRepository { 4 | // Get all cart items 5 | Future> fetchBanners(); 6 | } 7 | -------------------------------------------------------------------------------- /lib/data/repository/banner_repository/firebase_banner_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:e_commerce_app/data/models/models.dart'; 3 | 4 | import 'package:e_commerce_app/data/repository/banner_repository/banner_repo.dart'; 5 | 6 | /// Cart is collection in each user 7 | class FirebaseBannerRepository implements BannerRepository { 8 | @override 9 | Future> fetchBanners() async { 10 | return await FirebaseFirestore.instance 11 | .collection("banners") 12 | .get() 13 | .then((snapshot) => snapshot.docs 14 | .map((doc) => BannerModel.fromMap(doc.data()!)) 15 | .toList()) 16 | .catchError((err) {}); 17 | } 18 | 19 | ///Singleton factory 20 | static final FirebaseBannerRepository _instance = 21 | FirebaseBannerRepository._internal(); 22 | 23 | factory FirebaseBannerRepository() { 24 | return _instance; 25 | } 26 | 27 | FirebaseBannerRepository._internal(); 28 | } 29 | -------------------------------------------------------------------------------- /lib/data/repository/cart_repository/cart_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | 3 | abstract class CartRepository { 4 | /// Cart stream 5 | /// [uid] is user id 6 | /// Created by NDH 7 | Stream> fetchCart(String uid); 8 | 9 | /// Add item 10 | /// [uid] is user id 11 | /// [newItem] is data of new cart item 12 | /// Created by NDH 13 | Future addCartItemModel(String uid, CartItemModel newItem); 14 | 15 | /// Remove item 16 | /// [uid] is user id 17 | /// [cartItem] is data of cart item 18 | /// Created by NDH 19 | Future removeCartItemModel(String uid, CartItemModel cartItem); 20 | 21 | /// Clear cart 22 | /// [uid] is user id 23 | /// Created by NDH 24 | Future clearCart(String uid); 25 | 26 | /// Update quantity 27 | /// [uid] is user id 28 | /// [cartItem] is updated data of cart item 29 | /// Created by NDH 30 | Future updateCartItemModel(String uid, CartItemModel cartItem); 31 | } 32 | -------------------------------------------------------------------------------- /lib/data/repository/feedback_repository/feedback_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | 3 | abstract class FeedbackRepository { 4 | /// Stream of feedback 5 | /// [pid] is product id 6 | /// Created by NDH 7 | Stream>? fetchFeedbacks(String pid); 8 | 9 | /// Add new doc to feedbacks collection 10 | /// [pid] is product id 11 | /// [newItem] is data of new feedback 12 | /// Created by NDH 13 | Future addNewFeedback(String pid, FeedBackModel newItem); 14 | 15 | /// Get feedbacks by star 16 | /// [pid] is product id 17 | /// [star] is number of stars 18 | /// Created by NDH 19 | Future> getFeedbacksByStar(String pid, int star); 20 | } 21 | -------------------------------------------------------------------------------- /lib/data/repository/message_repository/message_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | 3 | abstract class MessageRepository { 4 | /// Get 20 first messages 5 | /// Created by NDH 6 | Stream> fetchRecentMessages({ 7 | required String uid, 8 | required int messagesLimit, 9 | }); 10 | 11 | /// Get more messages 12 | /// Created by NDH 13 | Future> fetchPreviousMessages({ 14 | required String uid, 15 | required int messagesLimit, 16 | required MessageModel lastMessage, 17 | }); 18 | 19 | /// Get lastest message 20 | /// Created by NDH 21 | Future getLastestMessage({required String uid}); 22 | 23 | /// Add message 24 | /// [uid] is user id 25 | /// [newItem] is data of new message 26 | /// Created by NDH 27 | Future addMessage(String uid, MessageModel message); 28 | 29 | /// Remove message 30 | /// [uid] is user id 31 | /// [cartItem] is data of message 32 | /// Created by NDH 33 | Future removeMessage(String uid, MessageModel message); 34 | } 35 | -------------------------------------------------------------------------------- /lib/data/repository/order_repository/firebase_order_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:e_commerce_app/data/models/models.dart'; 3 | import 'package:e_commerce_app/data/repository/order_repository/order_repo.dart'; 4 | 5 | /// cart is collection in each user 6 | class FirebaseOrderRepository implements OrderRepository { 7 | var orderCollection = FirebaseFirestore.instance.collection("orders"); 8 | 9 | /// Get all cart items 10 | Future> fetchOrders(String uid) async { 11 | return orderCollection 12 | .where("uid", isEqualTo: uid) 13 | .get() 14 | .then((snapshot) => snapshot.docs.map((doc) { 15 | var data = doc.data()!; 16 | return OrderModel.fromMap(data); 17 | }).toList()); 18 | } 19 | 20 | @override 21 | Future addOrderModel(OrderModel newOrderModel) async { 22 | await orderCollection.doc(newOrderModel.id).set(newOrderModel.toMap()); 23 | } 24 | 25 | @override 26 | Future removeOrderModel(OrderModel order) async { 27 | await orderCollection.doc(order.id).delete(); 28 | } 29 | 30 | ///Singleton factory 31 | static final FirebaseOrderRepository _instance = 32 | FirebaseOrderRepository._internal(); 33 | 34 | factory FirebaseOrderRepository() { 35 | return _instance; 36 | } 37 | 38 | FirebaseOrderRepository._internal(); 39 | } 40 | -------------------------------------------------------------------------------- /lib/data/repository/order_repository/order_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | 3 | abstract class OrderRepository { 4 | /// Get all orders 5 | /// [uid] is user id 6 | /// Created by NDH 7 | Future> fetchOrders(String uid); 8 | 9 | /// Add item 10 | /// [newOrderModel] is data of new order 11 | /// Created by NDH 12 | Future addOrderModel(OrderModel newOrderModel); 13 | 14 | /// Add item 15 | /// [newOrderModel] is data of new order 16 | /// Created by NDH 17 | Future removeOrderModel(OrderModel order); 18 | } 19 | -------------------------------------------------------------------------------- /lib/data/repository/product_repository/product_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | 3 | abstract class ProductRepository { 4 | /// Get all products 5 | /// Created by NDH 6 | Future> fetchProducts(); 7 | 8 | /// Get popular products 9 | /// Created by NDH 10 | Future> fetchPopularProducts(); 11 | 12 | /// Get discount products 13 | /// Created by NDH 14 | Future> fetchDiscountProducts(); 15 | 16 | /// Get products by category 17 | /// [categoryId] is id of category 18 | /// Created by NDH 19 | Future> fetchProductsByCategory(String? categoryId); 20 | 21 | /// Get product by Id 22 | /// [pid] is product id 23 | /// Created by NDH 24 | Future getProductById(String pid); 25 | 26 | /// Update product rating 27 | /// [pid] is product id 28 | /// [rating] is updated rating 29 | /// Created by NDH 30 | Future updateProductRatingById(String pid, double rating); 31 | 32 | /// Get all categories 33 | /// Created by NDH 34 | Future> getCategories(); 35 | 36 | /// Get category by id 37 | /// Created by NDH 38 | Future getCategoryById(String caregoryId); 39 | } 40 | -------------------------------------------------------------------------------- /lib/data/repository/repository.dart: -------------------------------------------------------------------------------- 1 | export 'user_repository/user_repo.dart'; 2 | export 'user_repository/firebase_user_repo.dart'; 3 | export 'auth_repository/auth_repo.dart'; 4 | export 'auth_repository/firebase_auth_repo.dart'; 5 | export 'product_repository/product_repo.dart'; 6 | export 'product_repository/firebase_product_repo.dart'; 7 | export 'banner_repository/banner_repo.dart'; 8 | export 'banner_repository/firebase_banner_repo.dart'; 9 | export 'cart_repository/cart_repo.dart'; 10 | export 'cart_repository/firebase_cart_repo.dart'; 11 | export 'order_repository/order_repo.dart'; 12 | export 'order_repository/firebase_order_repo.dart'; 13 | export 'feedback_repository/feedback_repo.dart'; 14 | export 'feedback_repository/firebase_feedback_repo.dart'; 15 | export 'message_repository/message_repo.dart'; 16 | export 'message_repository/firebase_message_repo.dart'; 17 | export 'storage_repository/storage_repo.dart'; 18 | export 'app_repository.dart'; 19 | -------------------------------------------------------------------------------- /lib/data/repository/storage_repository/storage_repo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:typed_data'; 3 | 4 | import 'package:firebase_storage/firebase_storage.dart'; 5 | 6 | class StorageRepository { 7 | static const String bucketRef = "gs://e-commerce-flutter-526ce.appspot.com"; 8 | FirebaseStorage storage = FirebaseStorage.instanceFor(bucket: bucketRef); 9 | 10 | /// Return image URL 11 | Future uploadImageFile(String ref, File file) async { 12 | var storageRef = storage.ref().child(ref); 13 | var uploadTask = await storageRef.putFile(file); 14 | 15 | String downloadURL = await uploadTask.ref.getDownloadURL(); 16 | return downloadURL; 17 | } 18 | 19 | /// Return photo URL 20 | Future uploadImageData(String ref, Uint8List fileData) async { 21 | var storageRef = storage.ref().child(ref); 22 | var uploadTask = await storageRef.putData(fileData); 23 | 24 | String downloadURL = await uploadTask.ref.getDownloadURL(); 25 | return downloadURL; 26 | } 27 | 28 | ///Singleton factory 29 | static final StorageRepository _instance = StorageRepository._internal(); 30 | 31 | factory StorageRepository() { 32 | return _instance; 33 | } 34 | 35 | StorageRepository._internal(); 36 | } 37 | -------------------------------------------------------------------------------- /lib/data/repository/user_repository/user_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:firebase_auth/firebase_auth.dart'; 3 | 4 | abstract class UserRepository { 5 | /// Stream of logged user model 6 | /// [loggedFirebaseUser] is user of firebase auth 7 | /// Created by NDH 8 | Stream loggedUserStream(User loggedFirebaseUser); 9 | 10 | /// Get user by id 11 | /// [uid] is user id 12 | /// Created by NDH 13 | Future getUserById(String uid); 14 | 15 | /// Add new doc to users collection 16 | /// [user] is data of new user 17 | /// Created by NDH 18 | Future addUserData(UserModel newUser); 19 | 20 | /// Update a doc in users collection 21 | /// [user] is updated data of user 22 | /// Created by NDH 23 | Future updateUserData(UserModel updatedUser); 24 | } 25 | -------------------------------------------------------------------------------- /lib/data/request/api_url.dart: -------------------------------------------------------------------------------- 1 | class DevEnvironment { 2 | final receiveTimeout = 2 * 60 * 1000; 3 | final connectTimeout = 2 * 60 * 1000; 4 | } 5 | 6 | class LocationApi { 7 | static const BASE_URL = "https://api.mysupership.vn/v1/partner/areas"; 8 | } 9 | 10 | final environment = DevEnvironment(); 11 | 12 | enum MethodType { GET, POST } 13 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | // @dart=2.9 2 | 3 | import 'package:e_commerce_app/presentation/common_blocs/common_bloc.dart'; 4 | import 'package:e_commerce_app/configs/config.dart'; 5 | import 'package:firebase_core/firebase_core.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter/services.dart'; 8 | import 'package:flutter_bloc/flutter_bloc.dart'; 9 | import 'package:e_commerce_app/app_view.dart'; 10 | import 'presentation/common_blocs/simple_bloc_observer.dart'; 11 | 12 | void main() async { 13 | WidgetsFlutterBinding.ensureInitialized(); 14 | SystemUiOverlayStyle(statusBarColor: Colors.transparent); 15 | Bloc.observer = SimpleBlocObserver(); 16 | await Firebase.initializeApp(); 17 | runApp(MyApp()); 18 | } 19 | 20 | // This widget is the root of your application. 21 | class MyApp extends StatelessWidget { 22 | @override 23 | Widget build(BuildContext context) { 24 | return MultiBlocProvider( 25 | providers: CommonBloc.blocProviders, 26 | child: LayoutBuilder( 27 | builder: (context, constraints) { 28 | return OrientationBuilder( 29 | builder: (context, orientation) { 30 | SizeConfig().init(constraints, orientation); 31 | return AppView(); 32 | }, 33 | ); 34 | }, 35 | ), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/application/application_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:e_commerce_app/presentation/common_blocs/common_bloc.dart'; 5 | import 'package:e_commerce_app/presentation/common_blocs/application/bloc.dart'; 6 | import 'package:e_commerce_app/presentation/common_blocs/auth/auth_event.dart'; 7 | import 'package:e_commerce_app/presentation/common_blocs/language/bloc.dart'; 8 | import 'package:e_commerce_app/data/local/pref.dart'; 9 | import 'package:e_commerce_app/configs/application.dart'; 10 | import 'package:flutter/material.dart'; 11 | 12 | class ApplicationBloc extends Bloc { 13 | final Application application = Application(); 14 | 15 | ApplicationBloc() : super(ApplicationInitial()); 16 | 17 | @override 18 | Stream mapEventToState(ApplicationEvent event) async* { 19 | if (event is SetupApplication) { 20 | /// Setup SharedPreferences 21 | await application.setPreferences(); 22 | 23 | /// Get old settings 24 | final oldLanguage = LocalPref.getString("language"); 25 | 26 | if (oldLanguage != null) { 27 | CommonBloc.languageBloc.add(LanguageChanged(Locale(oldLanguage))); 28 | } 29 | 30 | /// Authentication begin check 31 | CommonBloc.authencationBloc.add(AuthenticationStarted()); 32 | 33 | yield ApplicationCompleted(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/application/application_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class ApplicationEvent extends Equatable { 4 | const ApplicationEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class SetupApplication extends ApplicationEvent {} 11 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/application/application_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class ApplicationState extends Equatable { 4 | const ApplicationState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class ApplicationInitial extends ApplicationState {} 11 | 12 | class ApplicationCompleted extends ApplicationState {} 13 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/application/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'application_bloc.dart'; 2 | export 'application_event.dart'; 3 | export 'application_state.dart'; -------------------------------------------------------------------------------- /lib/presentation/common_blocs/auth/auth_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:e_commerce_app/data/repository/app_repository.dart'; 3 | import 'package:e_commerce_app/data/repository/repository.dart'; 4 | import 'package:e_commerce_app/presentation/common_blocs/auth/auth_event.dart'; 5 | 6 | import 'auth_state.dart'; 7 | 8 | class AuthenticationBloc 9 | extends Bloc { 10 | final AuthRepository _authRepository = AppRepository.authRepository; 11 | 12 | AuthenticationBloc() : super(Uninitialized()); 13 | 14 | @override 15 | Stream mapEventToState( 16 | AuthenticationEvent event) async* { 17 | if (event is AuthenticationStarted) { 18 | yield* _mapAppStartedToState(); 19 | } else if (event is LoggedIn) { 20 | yield* _mapLoggedInToState(); 21 | } else if (event is LoggedOut) { 22 | yield* _mapLoggedOutToState(); 23 | } 24 | } 25 | 26 | Stream _mapAppStartedToState() async* { 27 | try { 28 | bool isLoggedIn = _authRepository.isLoggedIn(); 29 | 30 | //For display splash screen 31 | await Future.delayed(Duration(seconds: 3)); 32 | 33 | if (isLoggedIn) { 34 | // Get current user 35 | final loggedFirebaseUser = _authRepository.loggedFirebaseUser; 36 | yield Authenticated(loggedFirebaseUser); 37 | } else { 38 | yield Unauthenticated(); 39 | } 40 | } catch (_) { 41 | yield Unauthenticated(); 42 | } 43 | } 44 | 45 | Stream _mapLoggedInToState() async* { 46 | yield Authenticated(_authRepository.loggedFirebaseUser); 47 | } 48 | 49 | Stream _mapLoggedOutToState() async* { 50 | yield Unauthenticated(); 51 | _authRepository.logOut(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/auth/auth_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class AuthenticationEvent extends Equatable { 4 | @override 5 | List get props => []; 6 | } 7 | 8 | class AuthenticationStarted extends AuthenticationEvent {} 9 | 10 | class LoggedIn extends AuthenticationEvent {} 11 | 12 | class LoggedOut extends AuthenticationEvent {} 13 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/auth/auth_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:firebase_auth/firebase_auth.dart'; 3 | 4 | abstract class AuthenticationState extends Equatable { 5 | const AuthenticationState(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | class Uninitialized extends AuthenticationState {} 12 | 13 | class Authenticated extends AuthenticationState { 14 | final User loggedFirebaseUser; 15 | 16 | const Authenticated(this.loggedFirebaseUser); 17 | 18 | @override 19 | List get props => [loggedFirebaseUser]; 20 | 21 | @override 22 | String toString() { 23 | return 'Authenticated{email: ${loggedFirebaseUser.email}}'; 24 | } 25 | } 26 | 27 | class Unauthenticated extends AuthenticationState {} 28 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/auth/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'auth_bloc.dart'; 2 | export 'auth_event.dart'; 3 | export 'auth_state.dart'; -------------------------------------------------------------------------------- /lib/presentation/common_blocs/cart/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'cart_bloc.dart'; 2 | export 'cart_event.dart'; 3 | export 'cart_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/cart/cart_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class CartEvent extends Equatable { 5 | const CartEvent(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | /// When open cart screen -> load cart event 12 | class LoadCart extends CartEvent {} 13 | 14 | /// When user clicks to a clear cart => clear cart event 15 | class ClearCart extends CartEvent {} 16 | 17 | /// Cart was cleared 18 | class CartUpdated extends CartEvent { 19 | final List updatedCart; 20 | 21 | CartUpdated(this.updatedCart); 22 | 23 | @override 24 | List get props => [updatedCart]; 25 | } 26 | 27 | /// When user clicks to add button => add cart item event 28 | class AddCartItemModel extends CartEvent { 29 | final CartItemModel cartItem; 30 | 31 | AddCartItemModel(this.cartItem); 32 | 33 | @override 34 | List get props => [cartItem]; 35 | } 36 | 37 | /// When user swipes to remove cart item => remove cart item event 38 | class RemoveCartItemModel extends CartEvent { 39 | final CartItemModel cartItem; 40 | 41 | RemoveCartItemModel(this.cartItem); 42 | 43 | @override 44 | List get props => [cartItem]; 45 | } 46 | 47 | /// When user clicks to change quantity => update cart event 48 | class UpdateCartItemModel extends CartEvent { 49 | final CartItemModel cartItem; 50 | 51 | UpdateCartItemModel(this.cartItem); 52 | 53 | @override 54 | List get props => [cartItem]; 55 | } 56 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/cart/cart_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class CartState extends Equatable { 5 | const CartState(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | /// Cart loading 12 | class CartLoading extends CartState {} 13 | 14 | /// Cart was loaded 15 | class CartLoaded extends CartState { 16 | final List cart; 17 | final int priceOfGoods; 18 | 19 | CartLoaded({ 20 | required this.cart, 21 | required this.priceOfGoods, 22 | }); 23 | 24 | @override 25 | List get props => [cart, priceOfGoods]; 26 | } 27 | 28 | /// Cart wasn't loaded 29 | class CartLoadFailure extends CartState { 30 | final String error; 31 | 32 | CartLoadFailure(this.error); 33 | 34 | @override 35 | List get props => [error]; 36 | } 37 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/language/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'language_bloc.dart'; 2 | export 'language_event.dart'; 3 | export 'language_state.dart'; -------------------------------------------------------------------------------- /lib/presentation/common_blocs/language/language_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/local/pref.dart'; 2 | import 'package:e_commerce_app/configs/config.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | 5 | import 'bloc.dart'; 6 | 7 | class LanguageBloc extends Bloc { 8 | LanguageBloc() : super(InitialLanguageState()); 9 | 10 | @override 11 | Stream mapEventToState(event) async* { 12 | if (event is LanguageChanged) { 13 | if (event.locale == AppLanguage.defaultLanguage) { 14 | yield LanguageUpdated(); 15 | } else { 16 | yield LanguageUpdating(); 17 | AppLanguage.defaultLanguage = event.locale; 18 | await LocalPref.setString("language", event.locale.languageCode); 19 | yield LanguageUpdated(); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/language/language_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | abstract class LanguageEvent extends Equatable {} 5 | 6 | class LanguageChanged extends LanguageEvent { 7 | final Locale locale; 8 | 9 | LanguageChanged(this.locale); 10 | 11 | @override 12 | List get props => [this.locale]; 13 | } 14 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/language/language_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class LanguageState extends Equatable{ 4 | @override 5 | List get props => []; 6 | } 7 | 8 | class InitialLanguageState extends LanguageState {} 9 | 10 | class LanguageUpdating extends LanguageState {} 11 | 12 | class LanguageUpdated extends LanguageState {} 13 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/order/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'order_bloc.dart'; 2 | export 'order_event.dart'; 3 | export 'order_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/order/order_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class OrderEvent extends Equatable { 5 | const OrderEvent(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | class LoadMyOrders extends OrderEvent {} 12 | 13 | class AddOrder extends OrderEvent { 14 | final OrderModel newOrderModel; 15 | 16 | AddOrder(this.newOrderModel); 17 | 18 | List get props => [newOrderModel]; 19 | } 20 | 21 | class RemoveOrder extends OrderEvent { 22 | final OrderModel order; 23 | 24 | RemoveOrder(this.order); 25 | 26 | List get props => [order]; 27 | } 28 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/order/order_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class OrderState extends Equatable { 5 | const OrderState(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | /// MyOrders loading 12 | class MyOrdersLoading extends OrderState {} 13 | 14 | /// MyOrders was loaded 15 | class MyOrdersLoaded extends OrderState { 16 | final List deliveringOrders; 17 | final List deliveredOrders; 18 | 19 | MyOrdersLoaded({ 20 | required this.deliveringOrders, 21 | required this.deliveredOrders, 22 | }); 23 | 24 | @override 25 | List get props => [this.deliveringOrders, this.deliveredOrders]; 26 | } 27 | 28 | /// MyOrders wasn't loaded 29 | class MyOrdersLoadFailure extends OrderState { 30 | final String error; 31 | 32 | MyOrdersLoadFailure(this.error); 33 | 34 | @override 35 | List get props => [error]; 36 | } 37 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/profile/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'profile_bloc.dart'; 2 | export 'profile_event.dart'; 3 | export 'profile_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/profile/profile_event.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:e_commerce_app/presentation/common_blocs/profile/bloc.dart'; 3 | import 'package:e_commerce_app/data/models/models.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | 6 | abstract class ProfileEvent extends Equatable { 7 | @override 8 | List get props => []; 9 | } 10 | 11 | /// Load profile of logged firebase user in firestore 12 | class LoadProfile extends ProfileEvent {} 13 | 14 | /// Upload user avatar 15 | class UploadAvatar extends ProfileEvent { 16 | final File imageFile; 17 | 18 | UploadAvatar(this.imageFile); 19 | 20 | List get props => [imageFile]; 21 | } 22 | 23 | /// Delivery addresses changed 24 | class AddressListChanged extends ProfileEvent { 25 | final DeliveryAddressModel deliveryAddress; 26 | final ListMethod method; 27 | 28 | AddressListChanged({required this.deliveryAddress, required this.method}); 29 | 30 | List get props => [deliveryAddress, method]; 31 | } 32 | 33 | /// Profile was updated 34 | class ProfileUpdated extends ProfileEvent { 35 | final UserModel updatedUser; 36 | 37 | ProfileUpdated(this.updatedUser); 38 | 39 | List get props => [updatedUser]; 40 | } 41 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/profile/profile_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class ProfileState extends Equatable { 5 | @override 6 | List get props => []; 7 | } 8 | 9 | class ProfileLoading extends ProfileState {} 10 | 11 | class ProfileLoaded extends ProfileState { 12 | final UserModel loggedUser; 13 | 14 | ProfileLoaded(this.loggedUser); 15 | 16 | List get props => [loggedUser]; 17 | 18 | @override 19 | String toString() { 20 | return "{ProfileLoaded: loggedUser:${this.loggedUser.toString()}}"; 21 | } 22 | } 23 | 24 | class ProfileLoadFailure extends ProfileState { 25 | final String error; 26 | 27 | ProfileLoadFailure(this.error); 28 | 29 | List get props => [error]; 30 | } 31 | -------------------------------------------------------------------------------- /lib/presentation/common_blocs/simple_bloc_observer.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:intl/intl.dart'; 3 | 4 | class SimpleBlocObserver extends BlocObserver { 5 | @override 6 | void onEvent(Bloc bloc, Object? event) { 7 | super.onEvent(bloc, event); 8 | log('onEvent', event); 9 | } 10 | 11 | @override 12 | void onTransition(Bloc bloc, Transition transition) { 13 | super.onTransition(bloc, transition); 14 | log( 15 | 'onTransition', 16 | '\tcurrentState=${transition.currentState}\n' 17 | '\tnextState=${transition.nextState}'); 18 | } 19 | 20 | void log(String name, Object? msg) { 21 | print( 22 | '===== ${DateFormat("HH:mm:ss-dd MMM, yyyy").format(DateTime.now())}: $name\n' 23 | '$msg'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/presentation/screens/cart/cart_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/constants/constants.dart'; 2 | import 'package:e_commerce_app/presentation/screens/cart/widgets/list_cart_item.dart'; 3 | import 'package:e_commerce_app/presentation/screens/cart/widgets/checkout_bottom.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:e_commerce_app/presentation/common_blocs/cart/bloc.dart'; 6 | import 'package:e_commerce_app/utils/utils.dart'; 7 | import 'package:flutter_bloc/flutter_bloc.dart'; 8 | 9 | class CartScreen extends StatelessWidget { 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | appBar: _buildAppBar(context), 14 | body: ListCartItemModel(), 15 | bottomNavigationBar: CheckoutBottom(), 16 | ); 17 | } 18 | 19 | _buildAppBar(BuildContext context) { 20 | return AppBar( 21 | title: Text(Translate.of(context).translate("cart")), 22 | actions: [ 23 | IconButton( 24 | icon: Icon(Icons.clear_all_rounded), 25 | onPressed: () => _onClearCart(context), 26 | ) 27 | ], 28 | ); 29 | } 30 | 31 | _onClearCart(BuildContext context) async { 32 | final response = await UtilDialog.showConfirmation( 33 | context, 34 | title: Translate.of(context).translate("clear_cart"), 35 | content: Text( 36 | Translate.of(context) 37 | .translate("all_cart_items_will_be_deleted_from_your_cart"), 38 | style: FONT_CONST.REGULAR_DEFAULT_20, 39 | ), 40 | confirmButtonText: Translate.of(context).translate("delete"), 41 | ) as bool; 42 | 43 | if (response) { 44 | BlocProvider.of(context).add(ClearCart()); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/presentation/screens/categories/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'categories_bloc.dart'; 2 | export 'categories_event.dart'; 3 | export 'categories_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/screens/categories/bloc/categories_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:e_commerce_app/presentation/screens/categories/bloc/bloc.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | 5 | class CategoriesEvent extends Equatable { 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class OpenScreen extends CategoriesEvent { 11 | final CategoryModel category; 12 | 13 | OpenScreen(this.category); 14 | 15 | @override 16 | List get props => [category]; 17 | 18 | @override 19 | String toString() { 20 | return 'OpenScreen{category: $category}'; 21 | } 22 | } 23 | 24 | class ClickIconSearch extends CategoriesEvent {} 25 | 26 | class ClickCloseSearch extends CategoriesEvent {} 27 | 28 | class SearchQueryChanged extends CategoriesEvent { 29 | final String keyword; 30 | 31 | SearchQueryChanged(this.keyword); 32 | 33 | @override 34 | List get props => [keyword]; 35 | 36 | @override 37 | String toString() { 38 | return 'SearchQueryChanged{keyword: $keyword}'; 39 | } 40 | } 41 | 42 | class ClickIconSort extends CategoriesEvent { 43 | @override 44 | List get props => [DateTime.now().millisecond]; 45 | } 46 | 47 | class CloseSortOption extends CategoriesEvent { 48 | @override 49 | List get props => [DateTime.now().millisecond]; 50 | } 51 | 52 | class SortOptionsChanged extends CategoriesEvent { 53 | final ProductSortOption productSortOption; 54 | 55 | SortOptionsChanged(this.productSortOption); 56 | 57 | @override 58 | List get props => [productSortOption]; 59 | 60 | @override 61 | String toString() { 62 | return 'SortByChanged{showSortBy: $productSortOption}'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/presentation/screens/categories/categories_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:e_commerce_app/configs/config.dart'; 3 | import 'package:e_commerce_app/presentation/screens/categories/bloc/bloc.dart'; 4 | import 'package:e_commerce_app/presentation/screens/categories/widgets/product_gallery.dart'; 5 | import 'package:e_commerce_app/presentation/screens/categories/widgets/toolbar.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter_bloc/flutter_bloc.dart'; 8 | 9 | class CategoriesScreen extends StatelessWidget { 10 | final CategoryModel category; 11 | 12 | const CategoriesScreen({ 13 | Key? key, 14 | required this.category, 15 | }) : super(key: key); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return BlocProvider( 20 | create: (context) => CategoriesBloc()..add(OpenScreen(category)), 21 | child: Scaffold( 22 | body: SafeArea( 23 | child: Column( 24 | children: [ 25 | ToolBarWidget(currCategoryModel: category), 26 | Expanded(child: ProductGallery()), 27 | ], 28 | ), 29 | ), 30 | ), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/presentation/screens/categories/widgets/grid_products.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:e_commerce_app/configs/size_config.dart'; 3 | import 'package:e_commerce_app/constants/constants.dart'; 4 | import 'package:e_commerce_app/presentation/widgets/custom_widgets.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | class GridProducts extends StatelessWidget { 8 | final List products; 9 | 10 | const GridProducts({Key? key, required this.products}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | if (products.isEmpty) { 15 | return Center( 16 | child: Image.asset( 17 | IMAGE_CONST.NOT_FOUND, 18 | width: SizeConfig.defaultSize * 25, 19 | height: SizeConfig.defaultSize * 25, 20 | ), 21 | ); 22 | } 23 | return GridView.builder( 24 | physics: BouncingScrollPhysics(), 25 | shrinkWrap: true, 26 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 27 | crossAxisCount: 2, 28 | childAspectRatio: 15 / 21, 29 | mainAxisSpacing: SizeConfig.defaultSize, 30 | crossAxisSpacing: 0, 31 | ), 32 | itemCount: products.length, 33 | itemBuilder: (context, index) { 34 | return ProductCard(product: products[index]); 35 | }, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/presentation/screens/delivery_address/address_picker/bloc/address_picker_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class AddressPickerEvent extends Equatable { 4 | const AddressPickerEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class InitialEvent extends AddressPickerEvent { 11 | final String? cityId; 12 | final String? districtId; 13 | 14 | InitialEvent({this.cityId, this.districtId}); 15 | } 16 | 17 | class LoadDistricts extends AddressPickerEvent { 18 | final String cityId; 19 | 20 | LoadDistricts(this.cityId); 21 | 22 | List get props => [cityId]; 23 | } 24 | 25 | class LoadWards extends AddressPickerEvent { 26 | final String districtId; 27 | 28 | LoadWards(this.districtId); 29 | 30 | List get props => [districtId]; 31 | } 32 | -------------------------------------------------------------------------------- /lib/presentation/screens/delivery_address/address_picker/bloc/address_picker_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/location_model.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | class AddressPickerState extends Equatable { 5 | final List cities; 6 | final List districts; 7 | final List wards; 8 | 9 | AddressPickerState({ 10 | this.cities = const [], 11 | this.districts = const [], 12 | this.wards = const [], 13 | }); 14 | 15 | AddressPickerState cloneWith({ 16 | List? cities, 17 | List? districts, 18 | List? wards, 19 | }) { 20 | return AddressPickerState( 21 | cities: cities ?? this.cities, 22 | districts: districts ?? this.districts, 23 | wards: wards ?? this.wards, 24 | ); 25 | } 26 | 27 | @override 28 | String toString() { 29 | return "AddressPickerState(cities: ${cities.length}, districts: ${districts.length}, wards: ${wards.length})"; 30 | } 31 | 32 | @override 33 | List get props => [cities, districts, wards]; 34 | } 35 | -------------------------------------------------------------------------------- /lib/presentation/screens/delivery_address/address_picker/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'address_picker_bloc.dart'; 2 | export 'address_picker_state.dart'; 3 | export 'address_picker_event.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/screens/detail_product/detail_product_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:e_commerce_app/presentation/screens/detail_product/widgets/app_bar.dart'; 3 | import 'package:e_commerce_app/presentation/screens/detail_product/widgets/product_images.dart'; 4 | import 'package:e_commerce_app/presentation/screens/detail_product/widgets/product_info.dart'; 5 | import 'package:e_commerce_app/presentation/screens/detail_product/widgets/related_products/related_products.dart'; 6 | import 'package:e_commerce_app/presentation/screens/detail_product/widgets/slogan.dart'; 7 | import 'package:flutter/cupertino.dart'; 8 | import 'package:flutter/material.dart'; 9 | import 'widgets/add_to_cart_nav.dart'; 10 | 11 | class DetailProductScreen extends StatelessWidget { 12 | final Product product; 13 | 14 | DetailProductScreen({Key? key, required this.product}) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | backgroundColor: Colors.white, 20 | body: SafeArea( 21 | child: Column( 22 | children: [ 23 | DetailProductAppBar(), 24 | Expanded( 25 | child: ListView( 26 | physics: BouncingScrollPhysics(), 27 | children: [ 28 | ProductImagesWidget(product: product), 29 | ProductInfoWidget(product: product), 30 | Slogan(), 31 | RelatedProducts(product: product), 32 | ], 33 | ), 34 | ) 35 | ], 36 | ), 37 | ), 38 | bottomNavigationBar: AddToCartNavigation(product: product), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/presentation/screens/detail_product/widgets/app_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/configs/size_config.dart'; 2 | import 'package:e_commerce_app/constants/color_constant.dart'; 3 | import 'package:e_commerce_app/constants/constants.dart'; 4 | import 'package:e_commerce_app/presentation/widgets/buttons/cart_button.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_svg/svg.dart'; 7 | 8 | class DetailProductAppBar extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return Padding( 12 | padding: EdgeInsets.symmetric( 13 | vertical: SizeConfig.defaultSize, 14 | horizontal: SizeConfig.defaultPadding, 15 | ), 16 | child: Row( 17 | children: [ 18 | _buildBackButton(context), 19 | Spacer(), 20 | CartButton(color: COLOR_CONST.textColor), 21 | ], 22 | ), 23 | ); 24 | } 25 | 26 | _buildBackButton(BuildContext context) { 27 | return GestureDetector( 28 | onTap: () { 29 | Navigator.pop(context); 30 | }, 31 | child: Container( 32 | height: SizeConfig.defaultSize * 4, 33 | width: SizeConfig.defaultSize * 4, 34 | padding: EdgeInsets.all(SizeConfig.defaultSize * 1.2), 35 | decoration: BoxDecoration( 36 | shape: BoxShape.circle, 37 | color: Color(0xFFF5F6F9), 38 | ), 39 | child: SvgPicture.asset(ICON_CONST.CANCEL), 40 | ), 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/presentation/screens/detail_product/widgets/related_products/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'related_products_bloc.dart'; 2 | export 'related_products_state.dart'; 3 | export 'related_products_event.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/screens/detail_product/widgets/related_products/bloc/related_products_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/repository/repository.dart'; 2 | import 'package:e_commerce_app/presentation/screens/detail_product/widgets/related_products/bloc/bloc.dart'; 3 | 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | 6 | class RelatedProductsBloc 7 | extends Bloc { 8 | ProductRepository _productRepository = AppRepository.productRepository; 9 | 10 | RelatedProductsBloc() : super(RelatedProductsLoading()); 11 | 12 | /// Map from load related products event to states 13 | @override 14 | Stream mapEventToState( 15 | RelatedProductsEvent event) async* { 16 | if (event is LoadRelatedProducts) { 17 | yield* _mapLoadRelatedProductsToState(event); 18 | } else if (event is OnSeeAll) { 19 | yield* _mapOnSeeAllToState(event); 20 | } 21 | } 22 | 23 | Stream _mapLoadRelatedProductsToState( 24 | LoadRelatedProducts event) async* { 25 | try { 26 | var products = await _productRepository.fetchProductsByCategory( 27 | event.product.categoryId, 28 | ); 29 | final relatedProducts = 30 | products.where((product) => product.id != event.product.id).toList(); 31 | yield RelatedProductsLoaded(relatedProducts); 32 | } catch (e) { 33 | yield RelatedProductsLoadFailure(e.toString()); 34 | } 35 | } 36 | 37 | Stream _mapOnSeeAllToState(OnSeeAll event) async* { 38 | try { 39 | var category = await _productRepository.getCategoryById(event.categoryId); 40 | yield GoToCategoriesScreen(category); 41 | } catch (e) {} 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/presentation/screens/detail_product/widgets/related_products/bloc/related_products_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class RelatedProductsEvent extends Equatable { 5 | const RelatedProductsEvent(); 6 | } 7 | 8 | /// When user clicks to a specific product => load related products 9 | class LoadRelatedProducts extends RelatedProductsEvent { 10 | final Product product; 11 | 12 | LoadRelatedProducts(this.product); 13 | 14 | @override 15 | List get props => [product]; 16 | } 17 | 18 | class OnSeeAll extends RelatedProductsEvent { 19 | final String categoryId; 20 | 21 | OnSeeAll(this.categoryId); 22 | 23 | @override 24 | List get props => [categoryId]; 25 | } 26 | -------------------------------------------------------------------------------- /lib/presentation/screens/detail_product/widgets/related_products/bloc/related_products_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:e_commerce_app/data/models/models.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | 5 | abstract class RelatedProductsState extends Equatable { 6 | const RelatedProductsState(); 7 | } 8 | 9 | /// When open detail product screen => loading related products state 10 | class RelatedProductsLoading extends RelatedProductsState { 11 | @override 12 | List get props => []; 13 | } 14 | 15 | /// When related products was loaded => related products loaded state 16 | class RelatedProductsLoaded extends RelatedProductsState { 17 | final List relatedProducts; 18 | 19 | RelatedProductsLoaded(this.relatedProducts); 20 | @override 21 | List get props => [relatedProducts]; 22 | } 23 | 24 | /// When related products wasn't loaded => related products not loaded state 25 | class RelatedProductsLoadFailure extends RelatedProductsState { 26 | final String error; 27 | 28 | RelatedProductsLoadFailure(this.error); 29 | @override 30 | List get props => [error]; 31 | } 32 | 33 | class GoToCategoriesScreen extends RelatedProductsState { 34 | final CategoryModel category; 35 | 36 | GoToCategoriesScreen(this.category); 37 | @override 38 | List get props => [category]; 39 | } 40 | -------------------------------------------------------------------------------- /lib/presentation/screens/detail_product/widgets/slogan.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/configs/size_config.dart'; 2 | import 'package:e_commerce_app/constants/constants.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_svg/svg.dart'; 5 | 6 | class Slogan extends StatelessWidget { 7 | @override 8 | Widget build(BuildContext context) { 9 | return Container( 10 | padding: EdgeInsets.symmetric( 11 | vertical: SizeConfig.defaultSize, 12 | horizontal: SizeConfig.defaultPadding, 13 | ), 14 | decoration: BoxDecoration( 15 | border: Border( 16 | top: BorderSide(color: Colors.black12, width: 1), 17 | bottom: BorderSide(color: Colors.black12, width: 1), 18 | ), 19 | ), 20 | child: Row( 21 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 22 | children: [ 23 | _buildSloganItem( 24 | iconPath: "assets/icons/return-free.svg", 25 | text: "Free return", 26 | ), 27 | _buildSloganItem( 28 | iconPath: "assets/icons/safety.svg", 29 | text: "Authentic 100%", 30 | ), 31 | _buildSloganItem( 32 | iconPath: "assets/icons/shipping.svg", 33 | text: "Fast delivery", 34 | ), 35 | ], 36 | ), 37 | ); 38 | } 39 | 40 | _buildSloganItem({required String iconPath, required String text}) { 41 | return Row( 42 | children: [ 43 | SvgPicture.asset( 44 | iconPath, 45 | width: SizeConfig.defaultSize * 3, 46 | height: SizeConfig.defaultSize * 3, 47 | color: COLOR_CONST.primaryColor, 48 | ), 49 | SizedBox(width: SizeConfig.defaultSize * 0.5), 50 | Text(text, style: FONT_CONST.REGULAR_DEFAULT_18), 51 | ], 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/presentation/screens/feedbacks/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'feedback_bloc.dart'; 2 | export 'feedback_event.dart'; 3 | export 'feedback_state.dart'; -------------------------------------------------------------------------------- /lib/presentation/screens/feedbacks/bloc/feedback_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | 3 | import 'package:equatable/equatable.dart'; 4 | 5 | abstract class FeedbacksEvent extends Equatable { 6 | const FeedbacksEvent(); 7 | 8 | @override 9 | List get props => []; 10 | } 11 | 12 | /// When open feedback screen 13 | class LoadFeedbacks extends FeedbacksEvent { 14 | final Product product; 15 | 16 | LoadFeedbacks(this.product); 17 | 18 | @override 19 | List get props => [product]; 20 | } 21 | 22 | class AddFeedback extends FeedbacksEvent { 23 | final String content; 24 | final int rating; 25 | 26 | AddFeedback({required this.content, required this.rating}); 27 | 28 | @override 29 | List get props => [content, rating]; 30 | } 31 | 32 | class StarChanged extends FeedbacksEvent { 33 | final int star; 34 | 35 | StarChanged(this.star); 36 | 37 | @override 38 | List get props => [star]; 39 | } 40 | 41 | class FeedbacksUpdated extends FeedbacksEvent { 42 | final List feedbacks; 43 | 44 | FeedbacksUpdated(this.feedbacks); 45 | 46 | @override 47 | List get props => [feedbacks]; 48 | } 49 | -------------------------------------------------------------------------------- /lib/presentation/screens/feedbacks/bloc/feedback_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class FeedbackState extends Equatable { 5 | const FeedbackState(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | /// Feedbacks loading 12 | class FeedbacksLoading extends FeedbackState {} 13 | 14 | /// Feedbacks was loaded 15 | class FeedbacksLoaded extends FeedbackState { 16 | final List feedbacks; 17 | final double rating; 18 | final int numberOfFeedbacks; 19 | 20 | FeedbacksLoaded(this.feedbacks, this.rating, this.numberOfFeedbacks); 21 | 22 | @override 23 | List get props => [feedbacks, rating, numberOfFeedbacks]; 24 | } 25 | 26 | /// Feedbacks wasn't loaded 27 | class FeedbacksLoadFailure extends FeedbackState { 28 | final String error; 29 | 30 | FeedbacksLoadFailure(this.error); 31 | 32 | @override 33 | List get props => [error]; 34 | } 35 | -------------------------------------------------------------------------------- /lib/presentation/screens/feedbacks/widgets/list_feedbacks.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/presentation/screens/feedbacks/bloc/bloc.dart'; 2 | import 'package:e_commerce_app/presentation/widgets/others/loading.dart'; 3 | import 'package:e_commerce_app/presentation/widgets/single_card/feedback_card.dart'; 4 | import 'package:e_commerce_app/utils/utils.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_bloc/flutter_bloc.dart'; 7 | 8 | class ListFeedbacks extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return BlocBuilder( 12 | builder: (context, state) { 13 | if (state is FeedbacksLoaded) { 14 | var feedbacks = state.feedbacks; 15 | return feedbacks.length > 0 16 | ? ListView.builder( 17 | physics: BouncingScrollPhysics(), 18 | itemCount: feedbacks.length, 19 | itemBuilder: (context, index) { 20 | return FeedbackCard(feedBack: feedbacks[index]); 21 | }, 22 | ) 23 | : Center( 24 | child: Text(Translate.of(context).translate("no_feedbacks")), 25 | ); 26 | } 27 | if (state is FeedbacksLoading) { 28 | return Loading(); 29 | } 30 | if (state is FeedbacksLoadFailure) { 31 | return Center(child: Text("Load Failure")); 32 | } 33 | 34 | return Center(child: Text("Something went wrongs.")); 35 | }, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/presentation/screens/forgot_password/forgot_password_screen.dart: -------------------------------------------------------------------------------- 1 | // import 'package:e_commerce_app/presentation/screens/forgot_password/widgets/body.dart'; 2 | // import 'package:flutter/material.dart'; 3 | 4 | // class ForgotPasswordScreen extends StatelessWidget { 5 | // static String routeName = "/forgot_password"; 6 | 7 | // @override 8 | // Widget build(BuildContext context) { 9 | // return Scaffold( 10 | // appBar: AppBar(title: Text("Forgot password")), 11 | // body: Body(), 12 | // ); 13 | // } 14 | // } 15 | -------------------------------------------------------------------------------- /lib/presentation/screens/forgot_password/widgets/body.dart: -------------------------------------------------------------------------------- 1 | // import 'package:e_commerce_app/constants/style_constant.dart'; 2 | // import 'package:e_commerce_app/presentation/screens/forgot_password/widgets/forgot_pass_form.dart'; 3 | // import 'package:flutter/material.dart'; 4 | 5 | // import 'package:e_commerce_app/configs/size_config.dart'; 6 | 7 | // class Body extends StatelessWidget { 8 | // @override 9 | // Widget build(BuildContext context) { 10 | // return SafeArea( 11 | // child: SizedBox( 12 | // width: double.infinity, 13 | // child: Padding( 14 | // padding: EdgeInsets.symmetric(horizontal: 20), 15 | // child: SingleChildScrollView( 16 | // child: Column( 17 | // children: [ 18 | // SizedBox(height: SizeConfig.screenHeight * 0.04), 19 | // Text( 20 | // "Forgot Password", 21 | // style: headingStyle(), 22 | // ), 23 | // Text( 24 | // "Don't worry! Please enter your email \nWe will send you a link to return to your account", 25 | // textAlign: TextAlign.center, 26 | // ), 27 | // SizedBox(height: SizeConfig.screenHeight * 0.08), 28 | // ForgotPassForm(), 29 | // SizedBox(height: SizeConfig.screenHeight * 0.04), 30 | // ], 31 | // ), 32 | // ), 33 | // ), 34 | // ), 35 | // ); 36 | // } 37 | // } 38 | -------------------------------------------------------------------------------- /lib/presentation/screens/home_page/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'home_bloc.dart'; 2 | export 'home_event.dart'; 3 | export 'home_state.dart'; -------------------------------------------------------------------------------- /lib/presentation/screens/home_page/bloc/home_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:e_commerce_app/data/repository/app_repository.dart'; 3 | import 'package:e_commerce_app/data/repository/repository.dart'; 4 | import 'package:e_commerce_app/presentation/screens/home_page/bloc/bloc.dart'; 5 | import 'package:flutter_bloc/flutter_bloc.dart'; 6 | 7 | class HomeBloc extends Bloc { 8 | final BannerRepository _bannerRepository = AppRepository.bannerRepository; 9 | final ProductRepository _productRepository = AppRepository.productRepository; 10 | 11 | HomeBloc() : super(HomeLoading()); 12 | 13 | @override 14 | Stream mapEventToState(HomeEvent event) async* { 15 | if (event is LoadHome) { 16 | yield* _mapLoadHomeToState(); 17 | } else if (event is RefreshHome) { 18 | yield HomeLoading(); 19 | yield* _mapLoadHomeToState(); 20 | } 21 | } 22 | 23 | Stream _mapLoadHomeToState() async* { 24 | try { 25 | HomeResponse homeResponse = HomeResponse( 26 | banners: await _bannerRepository.fetchBanners(), 27 | categories: await _productRepository.getCategories(), 28 | popularProducts: await _productRepository.fetchPopularProducts(), 29 | discountProducts: await _productRepository.fetchDiscountProducts(), 30 | ); 31 | yield HomeLoaded(homeResponse: homeResponse); 32 | } catch (e) { 33 | yield HomeLoadFailure(e.toString()); 34 | } 35 | } 36 | } 37 | 38 | class HomeResponse { 39 | final List banners; 40 | final List categories; 41 | final List popularProducts; 42 | final List discountProducts; 43 | 44 | HomeResponse({ 45 | required this.banners, 46 | required this.popularProducts, 47 | required this.categories, 48 | required this.discountProducts, 49 | }); 50 | } 51 | -------------------------------------------------------------------------------- /lib/presentation/screens/home_page/bloc/home_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class HomeEvent extends Equatable { 4 | const HomeEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class LoadHome extends HomeEvent {} 11 | 12 | class RefreshHome extends HomeEvent {} -------------------------------------------------------------------------------- /lib/presentation/screens/home_page/bloc/home_state.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:e_commerce_app/presentation/screens/home_page/bloc/bloc.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | 5 | abstract class HomeState extends Equatable { 6 | const HomeState(); 7 | 8 | @override 9 | List get props => []; 10 | } 11 | 12 | /// Loading 13 | class HomeLoading extends HomeState {} 14 | 15 | /// Adready data 16 | class HomeLoaded extends HomeState { 17 | final HomeResponse homeResponse; 18 | 19 | const HomeLoaded({required this.homeResponse}); 20 | 21 | @override 22 | List get props => [homeResponse]; 23 | } 24 | 25 | /// Failure 26 | class HomeLoadFailure extends HomeState { 27 | final String error; 28 | 29 | const HomeLoadFailure(this.error); 30 | } 31 | -------------------------------------------------------------------------------- /lib/presentation/screens/home_page/home_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/presentation/screens/home_page/bloc/bloc.dart'; 2 | import 'package:e_commerce_app/presentation/screens/home_page/widgets/home_body.dart'; 3 | import 'package:e_commerce_app/presentation/screens/home_page/widgets/home_header.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_bloc/flutter_bloc.dart'; 6 | 7 | class HomeScreen extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return BlocProvider( 11 | create: (context) => HomeBloc()..add(LoadHome()), 12 | child: Builder( 13 | builder: (context) { 14 | return Scaffold( 15 | body: SafeArea( 16 | child: RefreshIndicator( 17 | onRefresh: () async { 18 | BlocProvider.of(context).add(RefreshHome()); 19 | }, 20 | child: CustomScrollView( 21 | physics: AlwaysScrollableScrollPhysics( 22 | parent: BouncingScrollPhysics(), 23 | ), 24 | slivers: [ 25 | SliverPersistentHeader( 26 | delegate: HomePersistentHeader(), 27 | pinned: true, 28 | ), 29 | HomeBody(), 30 | ], 31 | ), 32 | ), 33 | ), 34 | ); 35 | }, 36 | ), 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/presentation/screens/initialize_info/widgets/initialize_info_header.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/constants/constants.dart'; 2 | import 'package:e_commerce_app/utils/utils.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:e_commerce_app/configs/size_config.dart'; 5 | 6 | class InitializeInfoHeader extends StatelessWidget { 7 | @override 8 | Widget build(BuildContext context) { 9 | return Container( 10 | width: double.infinity, 11 | padding: EdgeInsets.only( 12 | top: SizeConfig.defaultSize * 15, 13 | bottom: SizeConfig.defaultSize * 3, 14 | right: SizeConfig.defaultSize * 1.5, 15 | left: SizeConfig.defaultSize * 1.5, 16 | ), 17 | color: COLOR_CONST.primaryColor, 18 | child: Column( 19 | crossAxisAlignment: CrossAxisAlignment.start, 20 | children: [ 21 | Text( 22 | Translate.of(context).translate("complete_info"), 23 | style: FONT_CONST.BOLD_WHITE_32, 24 | ), 25 | Text( 26 | Translate.of(context).translate("it_so_quick_and_easy"), 27 | style: FONT_CONST.MEDIUM_WHITE_20, 28 | textAlign: TextAlign.center, 29 | ), 30 | ], 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/presentation/screens/login/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'login_bloc.dart'; 2 | export 'login_event.dart'; 3 | export 'login_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/screens/login/bloc/login_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class LoginEvent extends Equatable { 4 | const LoginEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | /// When user changes email 11 | class EmailChanged extends LoginEvent { 12 | final String email; 13 | 14 | const EmailChanged({required this.email}); 15 | 16 | @override 17 | List get props => [email]; 18 | 19 | @override 20 | String toString() { 21 | return 'EmailChanged{email: $email}'; 22 | } 23 | } 24 | 25 | /// When user changes password 26 | class PasswordChanged extends LoginEvent { 27 | final String password; 28 | 29 | const PasswordChanged({required this.password}); 30 | 31 | @override 32 | List get props => []; 33 | 34 | @override 35 | String toString() { 36 | return 'PasswordChanged{password: $password}'; 37 | } 38 | } 39 | 40 | /// When user clicks to login button 41 | class LoginWithCredential extends LoginEvent { 42 | final String email; 43 | final String password; 44 | 45 | LoginWithCredential({required this.email, required this.password}); 46 | 47 | @override 48 | List get props => [email, password]; 49 | } 50 | -------------------------------------------------------------------------------- /lib/presentation/screens/login/widgets/login_header.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/constants/color_constant.dart'; 2 | import 'package:e_commerce_app/constants/font_constant.dart'; 3 | import 'package:e_commerce_app/utils/translate.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:e_commerce_app/configs/size_config.dart'; 6 | 7 | class LoginHeader extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return Container( 11 | width: double.infinity, 12 | padding: EdgeInsets.only( 13 | top: SizeConfig.defaultSize * 15, 14 | bottom: SizeConfig.defaultSize * 3, 15 | right: SizeConfig.defaultSize * 1.5, 16 | left: SizeConfig.defaultSize * 1.5, 17 | ), 18 | color: COLOR_CONST.primaryColor, 19 | child: Column( 20 | crossAxisAlignment: CrossAxisAlignment.start, 21 | children: [ 22 | Text( 23 | Translate.of(context).translate("welcome_back"), 24 | style: FONT_CONST.BOLD_WHITE_32, 25 | ), 26 | Text( 27 | Translate.of(context).translate("login_slogan"), 28 | style: FONT_CONST.MEDIUM_WHITE_20, 29 | ), 30 | ], 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/presentation/screens/message/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'message_bloc.dart'; 2 | export 'message_state.dart'; 3 | export 'message_event.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/screens/message/bloc/message_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | import 'package:multi_image_picker/multi_image_picker.dart'; 4 | 5 | abstract class MessageEvent extends Equatable { 6 | const MessageEvent(); 7 | 8 | @override 9 | List get props => []; 10 | } 11 | 12 | /// Triggered load messages 13 | class LoadMessages extends MessageEvent {} 14 | 15 | /// Triggered load more messages 16 | class LoadPreviousMessages extends MessageEvent { 17 | final MessageModel lastMessage; 18 | 19 | LoadPreviousMessages(this.lastMessage); 20 | 21 | @override 22 | List get props => [lastMessage]; 23 | } 24 | 25 | /// When messages stream has new data 26 | class MessagesUpdated extends MessageEvent { 27 | final List messages; 28 | 29 | MessagesUpdated(this.messages); 30 | 31 | @override 32 | List get props => [messages]; 33 | } 34 | 35 | /// Triggered to send a text message 36 | class SendTextMessage extends MessageEvent { 37 | final String text; 38 | 39 | SendTextMessage({required this.text}); 40 | 41 | @override 42 | List get props => [text]; 43 | } 44 | 45 | /// Triggered to send a image message 46 | class SendImageMessage extends MessageEvent { 47 | final String? text; 48 | final List images; 49 | 50 | SendImageMessage({this.text, required this.images}); 51 | 52 | @override 53 | List get props => [images]; 54 | } 55 | 56 | /// Triggered to remove a message 57 | class RemoveMessage extends MessageEvent { 58 | final MessageModel message; 59 | 60 | RemoveMessage(this.message); 61 | 62 | @override 63 | List get props => [message]; 64 | } 65 | -------------------------------------------------------------------------------- /lib/presentation/screens/message/bloc/message_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class MessageState extends Equatable { 5 | const MessageState(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | ////////////////// 12 | class DisplayMessages extends MessageState { 13 | final List? messages; 14 | final bool hasReachedMax; 15 | final bool isPrevious; 16 | final String msg; 17 | final bool loading; 18 | 19 | DisplayMessages({ 20 | required this.messages, 21 | required this.hasReachedMax, 22 | required this.isPrevious, 23 | required this.msg, 24 | required this.loading, 25 | }); 26 | 27 | factory DisplayMessages.loading() { 28 | return DisplayMessages( 29 | msg: "", 30 | messages: null, 31 | hasReachedMax: false, 32 | isPrevious: false, 33 | loading: true, 34 | ); 35 | } 36 | 37 | factory DisplayMessages.data({ 38 | required List messages, 39 | required bool hasReachedMax, 40 | required bool isPrevious, 41 | }) { 42 | return DisplayMessages( 43 | msg: "", 44 | messages: messages, 45 | hasReachedMax: hasReachedMax, 46 | isPrevious: isPrevious, 47 | loading: false, 48 | ); 49 | } 50 | 51 | factory DisplayMessages.error(String msg) { 52 | return DisplayMessages( 53 | msg: msg, 54 | messages: null, 55 | hasReachedMax: false, 56 | isPrevious: false, 57 | loading: false, 58 | ); 59 | } 60 | 61 | @override 62 | List get props => [messages, hasReachedMax, loading, msg]; 63 | } 64 | -------------------------------------------------------------------------------- /lib/presentation/screens/register/register/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'register_bloc.dart'; 2 | export 'register_event.dart'; 3 | export 'register_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/screens/register/widgets/register_header.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/constants/constants.dart'; 2 | import 'package:e_commerce_app/utils/utils.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:e_commerce_app/configs/size_config.dart'; 5 | 6 | class RegisterHeader extends StatelessWidget { 7 | @override 8 | Widget build(BuildContext context) { 9 | return Container( 10 | width: double.infinity, 11 | padding: EdgeInsets.only( 12 | top: SizeConfig.defaultSize * 15, 13 | bottom: SizeConfig.defaultSize * 3, 14 | right: SizeConfig.defaultSize * 1.5, 15 | left: SizeConfig.defaultSize * 1.5, 16 | ), 17 | color: COLOR_CONST.primaryColor, 18 | child: Column( 19 | crossAxisAlignment: CrossAxisAlignment.start, 20 | children: [ 21 | Text( 22 | Translate.of(context).translate('register_now').toUpperCase(), 23 | style: FONT_CONST.BOLD_WHITE_32, 24 | ), 25 | Text( 26 | Translate.of(context).translate('it_so_quick_and_easy'), 27 | style: FONT_CONST.MEDIUM_WHITE_20, 28 | textAlign: TextAlign.center, 29 | ), 30 | ], 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/presentation/screens/search/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'search_bloc.dart'; 2 | export 'search_event.dart'; 3 | export 'search_state.dart'; -------------------------------------------------------------------------------- /lib/presentation/screens/search/bloc/search_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class SearchEvent extends Equatable { 4 | const SearchEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class OpenScreen extends SearchEvent {} 11 | 12 | class KeywordChanged extends SearchEvent { 13 | final String keyword; 14 | 15 | KeywordChanged(this.keyword); 16 | 17 | @override 18 | List get props => [this.keyword]; 19 | } 20 | -------------------------------------------------------------------------------- /lib/presentation/screens/search/bloc/search_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | 4 | abstract class SearchState extends Equatable { 5 | const SearchState(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | class Searching extends SearchState {} 12 | 13 | /// 14 | class SuggestionLoaded extends SearchState { 15 | final List recentKeywords; 16 | final List hotKeywords; 17 | 18 | SuggestionLoaded({required this.recentKeywords, required this.hotKeywords}); 19 | 20 | List get props => [this.recentKeywords, this.hotKeywords]; 21 | } 22 | 23 | /// 24 | class ResultsLoaded extends SearchState { 25 | final List results; 26 | 27 | ResultsLoaded(this.results); 28 | 29 | List get props => [this.results]; 30 | } 31 | 32 | /// 33 | class SearchFailure extends SearchState { 34 | final String error; 35 | 36 | SearchFailure(this.error); 37 | 38 | List get props => [this.error]; 39 | } 40 | -------------------------------------------------------------------------------- /lib/presentation/screens/search/widgets/suggestion.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/lib/presentation/screens/search/widgets/suggestion.dart -------------------------------------------------------------------------------- /lib/presentation/screens/splash/splash_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/constants/color_constant.dart'; 2 | import 'package:e_commerce_app/constants/constants.dart'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:e_commerce_app/configs/size_config.dart'; 6 | 7 | class SplashScreen extends StatelessWidget { 8 | @override 9 | Widget build(BuildContext context) { 10 | return Scaffold( 11 | backgroundColor: COLOR_CONST.primaryColor, 12 | body: SizedBox( 13 | width: double.infinity, 14 | child: Column( 15 | mainAxisAlignment: MainAxisAlignment.center, 16 | children: [ 17 | Image.asset( 18 | IMAGE_CONST.APP_LOGO, 19 | width: SizeConfig.defaultSize * 15, 20 | height: SizeConfig.defaultSize * 15, 21 | ), 22 | SizedBox(height: SizeConfig.defaultSize), 23 | CircularProgressIndicator( 24 | valueColor: AlwaysStoppedAnimation(Colors.white), 25 | ), 26 | ], 27 | ), 28 | ), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/presentation/widgets/buttons/cart_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/presentation/common_blocs/cart/bloc.dart'; 2 | import 'package:e_commerce_app/configs/router.dart'; 3 | import 'package:e_commerce_app/configs/size_config.dart'; 4 | import 'package:e_commerce_app/constants/constants.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_bloc/flutter_bloc.dart'; 7 | 8 | import 'icon_button_with_counter.dart'; 9 | 10 | class CartButton extends StatelessWidget { 11 | final Color color; 12 | 13 | const CartButton({ 14 | Key? key, 15 | this.color = COLOR_CONST.textColor, 16 | }) : super(key: key); 17 | @override 18 | Widget build(BuildContext context) { 19 | return BlocBuilder( 20 | buildWhen: (prevState, currState) => currState is CartLoaded, 21 | builder: (context, state) { 22 | return IconButtonWithCounter( 23 | icon: ICON_CONST.CART, 24 | onPressed: () => Navigator.pushNamed(context, AppRouter.CART), 25 | counter: state is CartLoaded ? state.cart.length : 0, 26 | size: SizeConfig.defaultSize * 3, 27 | color: color, 28 | ); 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/presentation/widgets/buttons/circle_icon_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/configs/size_config.dart'; 2 | import 'package:e_commerce_app/constants/color_constant.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_svg/svg.dart'; 5 | 6 | class CircleIconButton extends StatelessWidget { 7 | final double size; 8 | final Function? onPressed; 9 | final String svgIcon; 10 | final Color color; 11 | 12 | const CircleIconButton({ 13 | Key? key, 14 | required this.size, 15 | required this.svgIcon, 16 | this.onPressed, 17 | this.color = COLOR_CONST.secondaryColor, 18 | }) : super(key: key); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return InkWell( 23 | onTap: onPressed as void Function()?, 24 | child: Container( 25 | padding: EdgeInsets.all(SizeConfig.defaultSize), 26 | decoration: BoxDecoration( 27 | color: color, 28 | shape: BoxShape.circle, 29 | ), 30 | child: SvgPicture.asset( 31 | svgIcon, 32 | width: size, 33 | height: size, 34 | ), 35 | ), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/presentation/widgets/buttons/default_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:e_commerce_app/configs/size_config.dart'; 3 | import 'package:e_commerce_app/constants/color_constant.dart'; 4 | 5 | class DefaultButton extends StatelessWidget { 6 | final Function() onPressed; 7 | final Widget child; 8 | final Color backgroundColor; 9 | 10 | const DefaultButton({ 11 | Key? key, 12 | required this.onPressed, 13 | required this.child, 14 | this.backgroundColor = COLOR_CONST.primaryColor, 15 | }) : super(key: key); 16 | @override 17 | Widget build(BuildContext context) { 18 | return Container( 19 | width: double.infinity, 20 | height: SizeConfig.defaultSize * 5, 21 | child: TextButton( 22 | onPressed: onPressed, 23 | style: TextButton.styleFrom(backgroundColor: backgroundColor), 24 | child: child, 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/presentation/widgets/buttons/message_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/configs/config.dart'; 2 | import 'package:e_commerce_app/configs/size_config.dart'; 3 | import 'package:e_commerce_app/constants/color_constant.dart'; 4 | import 'package:e_commerce_app/constants/constants.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'icon_button_with_counter.dart'; 7 | 8 | class MessageButton extends StatelessWidget { 9 | final Color color; 10 | 11 | const MessageButton({ 12 | Key? key, 13 | this.color = COLOR_CONST.textColor, 14 | }) : super(key: key); 15 | @override 16 | Widget build(BuildContext context) { 17 | return IconButtonWithCounter( 18 | icon: ICON_CONST.MESSAGE, 19 | onPressed: () { 20 | Navigator.pushNamed(context, AppRouter.MESSAGES); 21 | }, 22 | counter: 0, 23 | size: SizeConfig.defaultSize * 3, 24 | color: color, 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/presentation/widgets/custom_widgets.dart: -------------------------------------------------------------------------------- 1 | export 'buttons/cart_button.dart'; 2 | export 'buttons/message_button.dart'; 3 | export 'buttons/circle_icon_button.dart'; 4 | export 'buttons/default_button.dart'; 5 | export 'buttons/icon_button_with_counter.dart'; 6 | export 'single_card/product_card.dart'; 7 | export 'single_card/category_card.dart'; 8 | export 'single_card/feedback_card.dart'; 9 | export 'single_card/cart_item_card.dart'; 10 | export 'single_card/delivery_address_card.dart'; 11 | export 'others/custom_card_widget.dart'; 12 | export 'others/loading.dart'; 13 | export 'others/rating_bar.dart'; 14 | export 'others/search_field_widget.dart'; 15 | export 'others/section_widget.dart'; 16 | export 'others/shimmer_image.dart'; 17 | export 'others/custom_list_tile.dart'; 18 | export 'others/text_row.dart'; 19 | -------------------------------------------------------------------------------- /lib/presentation/widgets/others/custom_dismissible.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CustomDismissible extends StatelessWidget { 4 | final Function(DismissDirection) onDismissed; 5 | final Widget child; 6 | final Icon? removeIcon; 7 | final Key key; 8 | 9 | const CustomDismissible({ 10 | required this.key, 11 | required this.onDismissed, 12 | required this.child, 13 | this.removeIcon, 14 | }) : super(key: key); 15 | @override 16 | Widget build(BuildContext context) { 17 | return Dismissible( 18 | key: key, 19 | direction: DismissDirection.endToStart, 20 | onDismissed: onDismissed, 21 | background: Container( 22 | padding: EdgeInsets.symmetric(horizontal: 40), 23 | decoration: BoxDecoration(color: Color(0xFFFFE6E6)), 24 | child: Row( 25 | children: [ 26 | Spacer(), 27 | removeIcon != null ? removeIcon! : Icon(Icons.remove), 28 | ], 29 | ), 30 | ), 31 | child: child, 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/presentation/widgets/others/loading.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/constants/constants.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class Loading extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Padding( 8 | padding: const EdgeInsets.all(10), 9 | child: Center( 10 | child: CircularProgressIndicator( 11 | valueColor: AlwaysStoppedAnimation(COLOR_CONST.primaryColor), 12 | ), 13 | ), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/presentation/widgets/others/payment_fees_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/presentation/widgets/custom_widgets.dart'; 2 | import 'package:e_commerce_app/utils/utils.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class PaymentFeesWidget extends StatelessWidget { 6 | final int priceOfGoods; 7 | final int deliveryFee; 8 | final int coupon; 9 | final int priceToBePaid; 10 | 11 | const PaymentFeesWidget({ 12 | Key? key, 13 | required this.priceOfGoods, 14 | required this.deliveryFee, 15 | required this.coupon, 16 | required this.priceToBePaid, 17 | }) : super(key: key); 18 | @override 19 | Widget build(BuildContext context) { 20 | return CustomCardWidget( 21 | child: Column( 22 | crossAxisAlignment: CrossAxisAlignment.start, 23 | children: [ 24 | TextRow( 25 | title: Translate.of(context).translate("total"), 26 | content: priceToBePaid.toPrice(), 27 | isSpaceBetween: true, 28 | ), 29 | TextRow( 30 | title: Translate.of(context).translate("price_of_goods"), 31 | content: priceOfGoods.toPrice(), 32 | ), 33 | TextRow( 34 | title: Translate.of(context).translate("delivery_fee"), 35 | content: deliveryFee.toPrice(), 36 | ), 37 | TextRow( 38 | title: Translate.of(context).translate("coupon"), 39 | content: coupon.toPrice(), 40 | ), 41 | ], 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/presentation/widgets/others/search_field_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/configs/size_config.dart'; 2 | import 'package:e_commerce_app/constants/constants.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class SearchFieldWidget extends StatelessWidget { 6 | final TextEditingController? searchController; 7 | final bool readOnly; 8 | final bool autoFocus; 9 | final Function()? onTap; 10 | final String? hintText; 11 | final double? height; 12 | 13 | const SearchFieldWidget({ 14 | Key? key, 15 | this.readOnly = false, 16 | this.autoFocus = false, 17 | this.onTap, 18 | this.searchController, 19 | this.hintText = "", 20 | this.height, 21 | }) : super(key: key); 22 | @override 23 | Widget build(BuildContext context) { 24 | return Container( 25 | height: height ?? SizeConfig.defaultSize * 5, 26 | decoration: BoxDecoration( 27 | borderRadius: BorderRadius.circular(SizeConfig.defaultSize * 2), 28 | color: COLOR_CONST.cardShadowColor.withOpacity(0.3), 29 | ), 30 | child: TextField( 31 | controller: searchController, 32 | keyboardType: TextInputType.text, 33 | autofocus: autoFocus, 34 | readOnly: readOnly, 35 | onTap: onTap, 36 | textAlignVertical: TextAlignVertical.center, 37 | decoration: InputDecoration( 38 | isDense: true, 39 | hintText: hintText, 40 | hintStyle: FONT_CONST.REGULAR_DEFAULT_20, 41 | prefixStyle: FONT_CONST.REGULAR_DEFAULT_20, 42 | contentPadding: EdgeInsets.all(0), 43 | prefixIcon: Icon(Icons.search), 44 | border: InputBorder.none, 45 | ), 46 | ), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/presentation/widgets/single_card/category_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/data/models/models.dart'; 2 | import 'package:e_commerce_app/constants/constants.dart'; 3 | import 'package:e_commerce_app/presentation/widgets/custom_widgets.dart'; 4 | import 'package:e_commerce_app/utils/utils.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | import 'package:e_commerce_app/configs/size_config.dart'; 8 | 9 | class CategoryModelCard extends StatelessWidget { 10 | const CategoryModelCard({ 11 | Key? key, 12 | required this.category, 13 | this.onPressed, 14 | }) : super(key: key); 15 | 16 | final CategoryModel category; 17 | final Function()? onPressed; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return GestureDetector( 22 | onTap: onPressed, 23 | child: Stack( 24 | children: [ 25 | ShimmerImage( 26 | borderRadius: BorderRadius.circular(5), 27 | imageUrl: category.imageUrl, 28 | ), 29 | Positioned( 30 | bottom: SizeConfig.defaultSize, 31 | left: SizeConfig.defaultSize * 2, 32 | child: Text( 33 | Translate.of(context).translate("${category.name}"), 34 | style: FONT_CONST.BOLD_WHITE_20, 35 | ), 36 | ), 37 | ], 38 | ), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/utils/app_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/utils/utils.dart'; 2 | 3 | extension PriceParsing on int { 4 | String toPrice() { 5 | return "${UtilFormatter.formatNumber(this)}₫"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /lib/utils/formatter.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:intl/intl.dart'; 3 | 4 | class UtilFormatter { 5 | static String formatNumber(int number) { 6 | final tool = new NumberFormat("#,##0", "en_US"); 7 | return tool.format(number).replaceAll(",", "."); 8 | } 9 | 10 | static String formatTimeStamp(Timestamp timestamp) { 11 | DateFormat formatter = DateFormat.yMMMMd().add_jm(); 12 | var date = 13 | new DateTime.fromMillisecondsSinceEpoch(timestamp.seconds * 1000); 14 | return formatter.format(date); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/utils/language.dart: -------------------------------------------------------------------------------- 1 | class UtilLanguage { 2 | ///Get Language Global Language Name 3 | static String getLanguageName(String code) { 4 | switch (code) { 5 | case 'en': 6 | return 'English'; 7 | case 'vi': 8 | return 'Vietnamese'; 9 | default: 10 | return 'English'; 11 | } 12 | } 13 | 14 | ///Singleton factory 15 | static final UtilLanguage _instance = UtilLanguage._internal(); 16 | 17 | factory UtilLanguage() { 18 | return _instance; 19 | } 20 | UtilLanguage._internal(); 21 | } 22 | -------------------------------------------------------------------------------- /lib/utils/toast.dart: -------------------------------------------------------------------------------- 1 | import 'package:e_commerce_app/configs/config.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fluttertoast/fluttertoast.dart'; 4 | 5 | class UtilToast { 6 | static void showMessageForUser(BuildContext context, String message) { 7 | Fluttertoast.showToast( 8 | msg: message, 9 | toastLength: Toast.LENGTH_SHORT, 10 | gravity: ToastGravity.CENTER, 11 | timeInSecForIosWeb: 1, 12 | backgroundColor: Colors.black.withOpacity(0.4), 13 | textColor: Colors.white, 14 | fontSize: SizeConfig.defaultSize * 1.6, 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/utils/translate.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:convert'; 3 | import 'package:flutter/services.dart' show rootBundle; 4 | import '../app_locale_delegate.dart'; 5 | 6 | class Translate{ 7 | final Locale locale; 8 | Map? _localizedStrings; 9 | static const LocalizationsDelegate delegate = AppLocaleDelegate(); 10 | 11 | Translate(this.locale); 12 | 13 | static Translate of(BuildContext context) { 14 | return Localizations.of(context, Translate)!; 15 | } 16 | 17 | Future load() async { 18 | String content = await rootBundle.loadString("assets/locale/${locale.languageCode}.json"); 19 | Map jsonMap = jsonDecode(content); 20 | 21 | _localizedStrings = jsonMap.map((key, value) { 22 | return MapEntry(key, value.toString()); 23 | }); 24 | 25 | return true; 26 | } 27 | 28 | String translate(String key) { 29 | return _localizedStrings![key] ?? key; 30 | } 31 | } -------------------------------------------------------------------------------- /lib/utils/utils.dart: -------------------------------------------------------------------------------- 1 | export 'validator.dart'; 2 | export 'formatter.dart'; 3 | export 'dialog.dart'; 4 | export 'translate.dart'; 5 | export 'language.dart'; 6 | export 'app_extension.dart'; 7 | -------------------------------------------------------------------------------- /lib/utils/validator.dart: -------------------------------------------------------------------------------- 1 | class UtilValidators { 2 | static final RegExp _emailRegExp = RegExp( 3 | r'^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$', 4 | ); 5 | static final RegExp _passwordRegExp = RegExp( 6 | r'^.{4,10}$', 7 | ); 8 | 9 | static final RegExp _phoneNumberRegExp = 10 | RegExp(r'^(03|05|07|08|09|01[2|6|8|9])+([0-9]{8})$'); 11 | 12 | static isValidEmail(String email) { 13 | return _emailRegExp.hasMatch(email); 14 | } 15 | 16 | static isVietnamesePhoneNumber(String phoneNumber) { 17 | return _phoneNumberRegExp.hasMatch(phoneNumber); 18 | } 19 | 20 | static isValidPassword(String password) { 21 | return _passwordRegExp.hasMatch(password); 22 | } 23 | 24 | static isValidName(String name) { 25 | return name.isNotEmpty; 26 | } 27 | 28 | ///Singleton factory 29 | static final UtilValidators _instance = UtilValidators._internal(); 30 | 31 | factory UtilValidators() { 32 | return _instance; 33 | } 34 | 35 | UtilValidators._internal(); 36 | } 37 | -------------------------------------------------------------------------------- /screenshots/add_address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/add_address.png -------------------------------------------------------------------------------- /screenshots/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/banner.png -------------------------------------------------------------------------------- /screenshots/cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/cart.png -------------------------------------------------------------------------------- /screenshots/delivery_address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/delivery_address.png -------------------------------------------------------------------------------- /screenshots/detail_product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/detail_product.png -------------------------------------------------------------------------------- /screenshots/empty_cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/empty_cart.png -------------------------------------------------------------------------------- /screenshots/feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/feedback.png -------------------------------------------------------------------------------- /screenshots/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/filter.png -------------------------------------------------------------------------------- /screenshots/grid_products.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/grid_products.png -------------------------------------------------------------------------------- /screenshots/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/home.png -------------------------------------------------------------------------------- /screenshots/language.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/language.png -------------------------------------------------------------------------------- /screenshots/list_product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/list_product.png -------------------------------------------------------------------------------- /screenshots/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/login.png -------------------------------------------------------------------------------- /screenshots/message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/message.png -------------------------------------------------------------------------------- /screenshots/no_product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/no_product.png -------------------------------------------------------------------------------- /screenshots/payment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/payment.png -------------------------------------------------------------------------------- /screenshots/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/profile.png -------------------------------------------------------------------------------- /screenshots/screens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/screens.png -------------------------------------------------------------------------------- /screenshots/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/search.png -------------------------------------------------------------------------------- /screenshots/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7wilightxdev/flutter_firebase_ecommerce/45e5001329ef9f831e376b69a11a098f66458ed3/screenshots/splash.png --------------------------------------------------------------------------------