├── .github └── workflows │ ├── appcenter_android.yml │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── design_sources ├── assets │ ├── black_shoes.png │ ├── credit_card.png │ ├── dress_image_cotton.png │ ├── dress_image_cotton2.png │ ├── dress_image_floral.png │ ├── dress_image_floral2.png │ ├── dress_image_pattern.png │ ├── dress_image_pattern2.png │ ├── girl1_image.png │ ├── girl2_image.png │ ├── girl3_image.png │ ├── gold_shoes.png │ ├── green_backpack.png │ ├── launch_icon_android.png │ ├── launch_icon_ios.png │ ├── pink_shoes.png │ ├── product_backpack.png │ ├── product_scarf.png │ ├── product_shirt.png │ ├── red_shoes.png │ ├── rose_red_shoes.png │ ├── sale.png │ ├── silver_shoes.png │ ├── white_shoes.png │ └── yellow_shoes.png ├── poster.jpg └── xd-resources-ecommerce-ui.zip └── ecommers ├── .gitignore ├── .metadata ├── .vs ├── ProjectSettings.json ├── VSWorkspaceState.json ├── ecommers │ └── v16 │ │ ├── .suo │ │ └── Browse.VC.db └── slnx.sqlite ├── .vscode └── launch.json ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── ecommers │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── add.svg ├── all_order.svg ├── apparel.svg ├── arrow_right.svg ├── back_icon.svg ├── bank_card.svg ├── beauty.svg ├── bell.svg ├── big_credit_card.png ├── check_form.svg ├── close_icon.svg ├── credit_card.svg ├── currency.svg ├── discuss_issue.svg ├── electronics.svg ├── filter_icon.svg ├── finished.svg ├── furniture.svg ├── home.svg ├── invite_friends.svg ├── language.svg ├── loader.flr ├── mail_icon.svg ├── menu_arrow.svg ├── messages.svg ├── notification_discount.svg ├── notification_location_pin.svg ├── notification_order.svg ├── notification_tag.svg ├── notifications.svg ├── password_icon.svg ├── payment.svg ├── pending_payment.svg ├── pending_shipments.svg ├── profile_icon.svg ├── rate_app.svg ├── rate_star.svg ├── remove.svg ├── right_icon.svg ├── sale.svg ├── search.svg ├── share_arrow.svg ├── shield.svg ├── shipping.svg ├── shoes.svg ├── splash_loader.flr ├── stationary.svg ├── success.flr ├── success.svg ├── suggest.svg ├── support.svg └── warning_icon.svg ├── i18n └── en-US.json ├── i18nconfig.json ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-50x50@1x.png │ │ ├── Icon-App-50x50@2x.png │ │ ├── Icon-App-57x57@1x.png │ │ ├── Icon-App-57x57@2x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-72x72@1x.png │ │ ├── Icon-App-72x72@2x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── core │ ├── app_services │ │ ├── app_service.dart │ │ ├── auth_response.dart │ │ ├── authorization_service.dart │ │ ├── category_service.dart │ │ ├── dialog │ │ │ ├── confirm_phone_registration.dart │ │ │ ├── confirmation_dialog.dart │ │ │ ├── dialog_base.dart │ │ │ └── dialog_service.dart │ │ ├── index.dart │ │ ├── note_service.dart │ │ ├── paginator.dart │ │ ├── payment_method_service.dart │ │ ├── product_service.dart │ │ ├── profile_service.dart │ │ └── shipping_address_service.dart │ ├── cache │ │ ├── cache_database.dart │ │ └── index.dart │ ├── common │ │ ├── api_defines.dart │ │ ├── api_query_params.dart │ │ ├── cache_defines.dart │ │ ├── categories.dart │ │ ├── file_manager.dart │ │ ├── index.dart │ │ ├── json_serializable_converter.dart │ │ ├── pages.dart │ │ ├── user_validator.dart │ │ └── validator │ │ │ ├── index.dart │ │ │ └── shipping_address_validator.dart │ ├── mixins │ │ ├── busy_notifier.dart │ │ ├── index.dart │ │ └── items_loading_notifier.dart │ ├── models │ │ ├── auth_rich_text_span_model.dart │ │ ├── cache_wrappers │ │ │ ├── categories_cache_wrapper.dart │ │ │ └── index.dart │ │ ├── data_models │ │ │ ├── category.dart │ │ │ ├── index.dart │ │ │ ├── note.dart │ │ │ ├── product.dart │ │ │ ├── product_color.dart │ │ │ ├── product_details.dart │ │ │ ├── product_model.dart │ │ │ ├── product_review.dart │ │ │ └── user.dart │ │ ├── index.dart │ │ ├── item_base.dart │ │ ├── login_model.dart │ │ ├── notification_model.dart │ │ ├── order_model.dart │ │ ├── page_arguments.dart │ │ ├── payment_method_model.dart │ │ ├── product_color_model.dart │ │ ├── product_size_model.dart │ │ ├── product_skuid_model.dart │ │ ├── shipping_address_model.dart │ │ ├── sort_type.dart │ │ └── user_model.dart │ ├── provider_models │ │ ├── auth │ │ │ ├── forgot_password_provider_model.dart │ │ │ ├── log_in_provider_model.dart │ │ │ └── sign_up_provider_model.dart │ │ ├── base_provider_model.dart │ │ ├── cart_provider.dart │ │ ├── categories_provider_model.dart │ │ ├── home_provider_model.dart │ │ ├── index.dart │ │ ├── more_provider_model.dart │ │ ├── payment_method_provider_model.dart │ │ ├── product_page_provider_model.dart │ │ ├── product_tab_provider_model.dart │ │ ├── products_grid_provder_model.dart │ │ ├── profile_provider_model.dart │ │ ├── search_page_provider_model.dart │ │ ├── search_query_provider_model.dart │ │ ├── shell_provider_model.dart │ │ └── shipping_address_provider_model.dart │ ├── repositories │ │ ├── cart_repository.dart │ │ ├── category_data_repository.dart │ │ ├── index.dart │ │ ├── payment_method_repository.dart │ │ ├── repository_base.dart │ │ └── shipping_address_repository.dart │ └── services │ │ ├── api_service.dart │ │ ├── index.dart │ │ ├── membership_service.dart │ │ └── navigation │ │ └── navigation_service.dart ├── data │ ├── repository │ │ ├── common.mappings.dart │ │ └── firebase_repository.dart │ └── result.dart ├── extensions │ ├── index.dart │ ├── json_extension.dart │ └── string_extension.dart ├── main.dart ├── shared │ ├── app_logger.dart │ ├── dependency_service.dart │ ├── get_it_extension.dart │ ├── i18n.dart │ └── logger.dart ├── ui │ ├── decorations │ │ ├── assets.dart │ │ ├── backgrounds_for_notifications.dart │ │ ├── branding_colors.dart │ │ ├── dimens │ │ │ ├── dimens.dart │ │ │ ├── font_sizes.dart │ │ │ ├── index.dart │ │ │ ├── insets.dart │ │ │ └── radiuses.dart │ │ ├── index.dart │ │ └── theme_provider.dart │ ├── pages │ │ ├── add_payment_method_page.dart │ │ ├── add_shipping_address_page.dart │ │ ├── authorization │ │ │ ├── authentication_tab_base.dart │ │ │ ├── authorization_page.dart │ │ │ ├── forgot_password_page.dart │ │ │ ├── index.dart │ │ │ ├── log_in_page.dart │ │ │ └── sign_up_page.dart │ │ ├── base_page.dart │ │ ├── busy_page.dart │ │ ├── cart_page.dart │ │ ├── categories_page.dart │ │ ├── checkout_page.dart │ │ ├── closeable_page.dart │ │ ├── home_page.dart │ │ ├── index.dart │ │ ├── more_page.dart │ │ ├── note_page.dart │ │ ├── notifications_page.dart │ │ ├── payment_method_page.dart │ │ ├── product_page.dart │ │ ├── products_grid_page.dart │ │ ├── profile_edit_page.dart │ │ ├── profile_page.dart │ │ ├── search_page.dart │ │ ├── shell_page.dart │ │ ├── shipping_address_page.dart │ │ └── success_page.dart │ ├── utils │ │ ├── formatter.dart │ │ └── index.dart │ └── widgets │ │ ├── address_card.dart │ │ ├── authorization │ │ ├── auth_form.dart │ │ ├── auth_rich_text.dart │ │ ├── auth_text_field.dart │ │ └── index.dart │ │ ├── back_button.dart │ │ ├── backgrounded_safe_area.dart │ │ ├── bank_card.dart │ │ ├── bottom_navigation │ │ ├── bottom_navigation_item_model.dart │ │ ├── bottom_navigation_widget.dart │ │ ├── buttom_bar_item_icon.dart │ │ └── consts.dart │ │ ├── button │ │ ├── button_base_widget.dart │ │ ├── index.dart │ │ ├── primary_button_widget.dart │ │ └── secondary_button_widget.dart │ │ ├── cached_image.dart │ │ ├── carousel_widget.dart │ │ ├── category │ │ ├── categories_compact_view.dart │ │ ├── category_item.dart │ │ └── sub_category_list.dart │ │ ├── circle_icon.dart │ │ ├── credit_card_text_field.dart │ │ ├── hero_image.dart │ │ ├── icon_with_badge.dart │ │ ├── image_card.dart │ │ ├── index.dart │ │ ├── items_loader.dart │ │ ├── menu │ │ ├── index.dart │ │ ├── menu_item.dart │ │ ├── menu_item_model.dart │ │ └── menu_list.dart │ │ ├── notes_carousel.dart │ │ ├── notification │ │ └── notification_widget.dart │ │ ├── order │ │ ├── circle_image.dart │ │ ├── counter.dart │ │ ├── index.dart │ │ ├── order_widget.dart │ │ ├── small_order_widget.dart │ │ └── total_order_widget.dart │ │ ├── product_item │ │ ├── index.dart │ │ ├── product_item_base.dart │ │ ├── product_item_normal.dart │ │ ├── product_item_small.dart │ │ └── product_item_wide.dart │ │ ├── product_latest_grid.dart │ │ ├── product_page │ │ ├── details_tab.dart │ │ ├── header.dart │ │ ├── index.dart │ │ ├── product_page_bottom_view.dart │ │ ├── product_tab.dart │ │ └── reviews_tab.dart │ │ ├── products_grid.dart │ │ ├── profile │ │ └── profile_image.dart │ │ ├── progress.dart │ │ ├── rate_widget.dart │ │ ├── right_menu_bar │ │ ├── index.dart │ │ ├── models │ │ │ ├── carousel_image.dart │ │ │ ├── index.dart │ │ │ ├── right_menu_colors_model.dart │ │ │ ├── right_menu_item_model.dart │ │ │ ├── right_menu_price_model.dart │ │ │ └── right_menu_subtitle_model.dart │ │ ├── right_menu_item.dart │ │ ├── right_menu_items_list.dart │ │ ├── right_menu_widget.dart │ │ └── subtitle_factory.dart │ │ ├── search │ │ ├── container_with_action.dart │ │ ├── index.dart │ │ ├── recent_product_list.dart │ │ ├── search_button.dart │ │ ├── search_recommended_widget.dart │ │ └── search_text_field.dart │ │ ├── shipping_address_text_field.dart │ │ ├── slide_menu.dart │ │ └── surface_container.dart └── web_server │ ├── config.dart │ ├── data │ ├── categories.json │ ├── notes.json │ └── products.json │ ├── data_access │ ├── products_data_access.dart │ ├── user_data_access.dart │ └── validation_model.dart │ ├── local_database.dart │ ├── local_server.dart │ ├── query_params │ ├── index.dart │ ├── latest_product_query_params.dart │ └── product_query_params.dart │ ├── request_handler.dart │ └── services │ ├── authorization_service.dart │ ├── data_provider.dart │ └── product_comparator.dart ├── pubspec.yaml ├── runner └── test └── widget_test.dart /.github/workflows/appcenter_android.yml: -------------------------------------------------------------------------------- 1 | name: Build and push Android 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v1 15 | - uses: actions/setup-java@v1 16 | with: 17 | java-version: '12.x' 18 | - name: Cache Flutter Dependencies 19 | uses: actions/cache@v1 20 | with: 21 | path: /opt/hostedtoolcache/flutter 22 | key: ${{ runner.os }}-flutter 23 | - uses: subosito/flutter-action@v1 24 | with: 25 | channel: 'dev' # or: 'dev' or 'beta' 26 | - name: Install dependencies 27 | run: flutter pub get 28 | working-directory: ecommers 29 | - name: generate files 30 | run: flutter packages pub run build_runner build --delete-conflicting-outputs 31 | working-directory: ecommers 32 | - name: Build Android app 33 | run: flutter build apk --target-platform android-arm 34 | working-directory: ecommers 35 | - name: upload artefact to App Center 36 | uses: wzieba/AppCenter-Github-Action@v1.0.0 37 | with: 38 | appName: EPAM/Flutter-eCom-Android 39 | token: ${{secrets.AM_android_appcenter}} 40 | group: Testers 41 | file: ecommers/build/app/outputs/apk/release/app-release.apk 42 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: build and check Android 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - dev 7 | - master 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2.1.0 16 | - name: setup google services json 17 | uses: DamianReeves/write-file-action@v1.0 18 | with: 19 | path: /home/runner/work/flutter-ecommers-sample/flutter-ecommers-sample/ecommers/android/app/google-services.json 20 | contents: 21 | ${{secrets.android_google_services}} 22 | write-mode: overwrite 23 | - uses: actions/setup-java@v1 24 | with: 25 | java-version: '12.x' 26 | - name: Cache Flutter Dependencies 27 | uses: actions/cache@v1 28 | with: 29 | path: /opt/hostedtoolcache/flutter 30 | key: ${{ runner.os }}-flutter 31 | - uses: subosito/flutter-action@v1 32 | with: 33 | channel: 'dev' # or: 'dev' or 'beta' 34 | - name: Install dependencies 35 | run: flutter pub get 36 | working-directory: ecommers 37 | - name: generate files 38 | run: flutter packages pub run build_runner build --delete-conflicting-outputs 39 | working-directory: ecommers 40 | - name: Build Android app 41 | run: flutter build apk --target-platform android-arm 42 | working-directory: ecommers 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Cloth Shop](https://github.com/epam-cross-platform-lab/flutter-ecommers-sample/blob/dev/design_sources/poster.jpg)](https://github.com/epam-cross-platform-lab/flutter-ecommers-sample) 2 | 3 | # Cloth Shop - Flutter [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/epam-cross-platform-lab/flutter-ecommers-sample) [![GitHub version](https://d25lcipzij17d.cloudfront.net/badge.svg?id=gh&type=6&v=1.0&x2=0)](https://github.com/mkiisoft/FlutterMovieTrends) 4 | 5 | Cloth Shop it's an example using Flutter for Android and iOS. 6 | 7 | ## About 8 | 9 | This repository serves the source code for the Ecommers sample mobile app for iOS and Android. 10 | 11 | ## Getting Started 12 | 13 | 1. Ensure Flutter SDK is installed correctly, ``flutter doctor`` 14 | 2. Fetch dependent Dart/Flutter packages, ``flutter pub get`` 15 | 3. Due to we use compile-time JSON serialization and API client *code generation*, run ``flutter packages pub run build_runner build --delete-conflicting-outputs`` which recreates all necessary files 16 | 4. Install https://marketplace.visualstudio.com/items?itemName=esskar.vscode-flutter-i18n-json extension for updating json strings 17 | 5. Add GoogleService-info.plist to ios/Runner and update CFBundleURLTypes *id* in Info.plist 18 | 6. Add Google-Service.json to android/app 19 | 20 | # Features 21 | 22 | * Firebase (under development) 23 | * Login Screen 24 | * Loading Screen 25 | * Grid and List views 26 | * Nested Scroll views 27 | * Pagination (under development) 28 | * Local http server 29 | * Async tasks 30 | * Custom Views 31 | * Intent Uri launcher (under development) 32 | 33 | ## Getting Started 34 | 35 | For help getting started with Flutter, view our online 36 | [documentation](https://flutter.io/). 37 | 38 | # © 2020 Epam Systems 39 | -------------------------------------------------------------------------------- /design_sources/assets/black_shoes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/black_shoes.png -------------------------------------------------------------------------------- /design_sources/assets/credit_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/credit_card.png -------------------------------------------------------------------------------- /design_sources/assets/dress_image_cotton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/dress_image_cotton.png -------------------------------------------------------------------------------- /design_sources/assets/dress_image_cotton2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/dress_image_cotton2.png -------------------------------------------------------------------------------- /design_sources/assets/dress_image_floral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/dress_image_floral.png -------------------------------------------------------------------------------- /design_sources/assets/dress_image_floral2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/dress_image_floral2.png -------------------------------------------------------------------------------- /design_sources/assets/dress_image_pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/dress_image_pattern.png -------------------------------------------------------------------------------- /design_sources/assets/dress_image_pattern2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/dress_image_pattern2.png -------------------------------------------------------------------------------- /design_sources/assets/girl1_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/girl1_image.png -------------------------------------------------------------------------------- /design_sources/assets/girl2_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/girl2_image.png -------------------------------------------------------------------------------- /design_sources/assets/girl3_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/girl3_image.png -------------------------------------------------------------------------------- /design_sources/assets/gold_shoes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/gold_shoes.png -------------------------------------------------------------------------------- /design_sources/assets/green_backpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/green_backpack.png -------------------------------------------------------------------------------- /design_sources/assets/launch_icon_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/launch_icon_android.png -------------------------------------------------------------------------------- /design_sources/assets/launch_icon_ios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/launch_icon_ios.png -------------------------------------------------------------------------------- /design_sources/assets/pink_shoes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/pink_shoes.png -------------------------------------------------------------------------------- /design_sources/assets/product_backpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/product_backpack.png -------------------------------------------------------------------------------- /design_sources/assets/product_scarf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/product_scarf.png -------------------------------------------------------------------------------- /design_sources/assets/product_shirt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/product_shirt.png -------------------------------------------------------------------------------- /design_sources/assets/red_shoes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/red_shoes.png -------------------------------------------------------------------------------- /design_sources/assets/rose_red_shoes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/rose_red_shoes.png -------------------------------------------------------------------------------- /design_sources/assets/sale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/sale.png -------------------------------------------------------------------------------- /design_sources/assets/silver_shoes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/silver_shoes.png -------------------------------------------------------------------------------- /design_sources/assets/white_shoes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/white_shoes.png -------------------------------------------------------------------------------- /design_sources/assets/yellow_shoes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/assets/yellow_shoes.png -------------------------------------------------------------------------------- /design_sources/poster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/poster.jpg -------------------------------------------------------------------------------- /design_sources/xd-resources-ecommerce-ui.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/design_sources/xd-resources-ecommerce-ui.zip -------------------------------------------------------------------------------- /ecommers/.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 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Exceptions to above rules. 37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 38 | -------------------------------------------------------------------------------- /ecommers/.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: fabf4e3d0d311181178d2c601d29a2f739ea543a 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /ecommers/.vs/ProjectSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "CurrentProjectSetting": "No Configurations" 3 | } -------------------------------------------------------------------------------- /ecommers/.vs/VSWorkspaceState.json: -------------------------------------------------------------------------------- 1 | { 2 | "ExpandedNodes": [ 3 | "" 4 | ], 5 | "PreviewInSolutionExplorer": false 6 | } -------------------------------------------------------------------------------- /ecommers/.vs/ecommers/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/.vs/ecommers/v16/.suo -------------------------------------------------------------------------------- /ecommers/.vs/ecommers/v16/Browse.VC.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/.vs/ecommers/v16/Browse.VC.db -------------------------------------------------------------------------------- /ecommers/.vs/slnx.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/.vs/slnx.sqlite -------------------------------------------------------------------------------- /ecommers/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Flutter", 9 | "request": "launch", 10 | "type": "dart" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /ecommers/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lint/analysis_options.yaml 2 | 3 | analyzer: 4 | exclude: 5 | - lib/generated/i18n.dart 6 | - lib/**.g.dart 7 | - lib/**.chopper.dart 8 | errors: 9 | todo: warning 10 | 11 | linter: 12 | rules: 13 | prefer_single_quotes: true 14 | avoid_classes_with_only_static_members: false -------------------------------------------------------------------------------- /ecommers/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /ecommers/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ecommers/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ecommers/android/app/src/main/kotlin/com/example/ecommers/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.ecommers.sample 2 | 3 | import androidx.annotation.NonNull; 4 | import io.flutter.embedding.android.FlutterActivity 5 | import io.flutter.embedding.engine.FlutterEngine 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 10 | GeneratedPluginRegistrant.registerWith(flutterEngine); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ecommers/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ecommers/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /ecommers/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /ecommers/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ecommers/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ecommers/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ecommers/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /ecommers/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ecommers/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | maven { 7 | url 'https://maven.fabric.io/public' 8 | } 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:3.5.3' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | classpath 'com.google.gms:google-services:4.3.3' 15 | classpath 'io.fabric.tools:gradle:1.26.1' 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | google() 22 | jcenter() 23 | } 24 | } 25 | 26 | rootProject.buildDir = '../build' 27 | subprojects { 28 | project.buildDir = "${rootProject.buildDir}/${project.name}" 29 | } 30 | subprojects { 31 | project.evaluationDependsOn(':app') 32 | } 33 | 34 | task clean(type: Delete) { 35 | delete rootProject.buildDir 36 | } 37 | -------------------------------------------------------------------------------- /ecommers/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /ecommers/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-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /ecommers/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /ecommers/assets/all_order.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ecommers/assets/apparel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ecommers/assets/arrow_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ecommers/assets/back_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/beauty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ecommers/assets/bell.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/big_credit_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/assets/big_credit_card.png -------------------------------------------------------------------------------- /ecommers/assets/check_form.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ecommers/assets/close_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/credit_card.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ecommers/assets/currency.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/discuss_issue.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/electronics.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ecommers/assets/filter_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/finished.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/furniture.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ecommers/assets/home.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ecommers/assets/invite_friends.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/language.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ecommers/assets/loader.flr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/assets/loader.flr -------------------------------------------------------------------------------- /ecommers/assets/mail_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ecommers/assets/notification_location_pin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ecommers/assets/notification_order.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ecommers/assets/notification_tag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ecommers/assets/notifications.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/password_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ecommers/assets/pending_payment.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/pending_shipments.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/profile_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/rate_app.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/rate_star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/remove.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/right_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ecommers/assets/sale.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/share_arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ecommers/assets/shield.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ecommers/assets/shipping.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ecommers/assets/shoes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ecommers/assets/splash_loader.flr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/assets/splash_loader.flr -------------------------------------------------------------------------------- /ecommers/assets/stationary.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ecommers/assets/success.flr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/assets/success.flr -------------------------------------------------------------------------------- /ecommers/assets/success.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/suggest.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ecommers/assets/support.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ecommers/assets/warning_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ecommers/i18nconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultLocale": "en-US", 3 | "locales": [ 4 | "en-US" 5 | ], 6 | "localePath": "i18n", 7 | "generatedPath": "lib/shared", 8 | "ltr": [ 9 | "en-US" 10 | ], 11 | "rtl": [] 12 | } -------------------------------------------------------------------------------- /ecommers/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 | -------------------------------------------------------------------------------- /ecommers/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 | -------------------------------------------------------------------------------- /ecommers/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ecommers/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ecommers/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ecommers/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ecommers/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ecommers/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 | -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ecommers/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 | -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ecommers/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epam-cross-platform-lab/flutter-ecommers-sample/ad9fac52e53d22514834aee447b602cc0b775148/ecommers/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ecommers/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. -------------------------------------------------------------------------------- /ecommers/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 | -------------------------------------------------------------------------------- /ecommers/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/app_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:chopper/chopper.dart'; 2 | 3 | class AppService { 4 | Future fetchData( 5 | Future> Function() requestFunction) async { 6 | final response = await requestFunction(); 7 | 8 | if (response.isSuccessful) { 9 | return response.body; 10 | } 11 | 12 | return null; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/auth_response.dart: -------------------------------------------------------------------------------- 1 | class AuthResponse { 2 | final bool isSuccessful; 3 | final String error; 4 | 5 | AuthResponse({this.isSuccessful, this.error}); 6 | } 7 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/authorization_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:ecommers/data/repository/firebase_repository.dart'; 4 | import 'package:ecommers/shared/dependency_service.dart'; 5 | 6 | class AuthorizationService { 7 | Future signInWithEmailAndPassword( 8 | String email, String password) async { 9 | final result = 10 | await authRepository.signInWithEmailAndPassword(email, password); 11 | 12 | if (result.status == AuthStatus.success) { 13 | membershipService.refresh(result.data); 14 | } 15 | 16 | return result.status; 17 | } 18 | 19 | Future updateUserName(String username) { 20 | return authRepository.updateUsername(username); 21 | } 22 | 23 | Future signInWithPhone(String phone) async { 24 | final result = await authRepository.signInWithPhoneNumber(phone); 25 | if (result.status == AuthStatus.success) { 26 | membershipService.refresh(result.data); 27 | } 28 | 29 | return result.status; 30 | } 31 | 32 | Future createUserWithEmailAndPassword( 33 | String email, String password) async { 34 | final result = 35 | await authRepository.registerWithEmailAndPassword(email, password); 36 | if (result.status == AuthStatus.success) { 37 | membershipService.refresh(result.data); 38 | } 39 | 40 | return result.status; 41 | } 42 | 43 | Future restorePassword(String email) async { 44 | return authRepository.restorePassword(email); 45 | } 46 | 47 | Future logOut() async { 48 | membershipService.clear(); 49 | await authRepository.logout(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/category_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/data_models/index.dart'; 2 | import 'package:ecommers/shared/dependency_service.dart'; 3 | 4 | class CategoryService { 5 | Future> fetchCategoryList() async => categoryDataRepository.getCategories(); 6 | } 7 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/dialog/confirm_phone_registration.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/app_services/dialog/dialog_base.dart'; 2 | import 'package:ecommers/shared/dependency_service.dart'; 3 | import 'package:ecommers/ui/decorations/index.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class ConfirmPhoneRegistration extends DialogBase { 7 | @override 8 | String get defaultValue => null; 9 | 10 | Future showDialog() { 11 | final codeController = TextEditingController(); 12 | 13 | return showInternally(AlertDialog( 14 | title: Text( 15 | localization.enter_sms_code_dialogTitle, 16 | style: textTheme.headline5, 17 | ), 18 | content: Column( 19 | mainAxisSize: MainAxisSize.min, 20 | children: [ 21 | TextField(controller: codeController), 22 | ], 23 | ), 24 | actions: [ 25 | FlatButton( 26 | textColor: Colors.white, 27 | color: BrandingColors.primary, 28 | onPressed: () => dismissDialog(codeController.text), 29 | child: Text(localization.enter_sms_code_dialogPrimary_button), 30 | ) 31 | ], 32 | )); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/dialog/confirmation_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:ecommers/core/app_services/dialog/dialog_base.dart'; 4 | import 'package:ecommers/shared/dependency_service.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter/widgets.dart'; 7 | 8 | class ConfirmationDialog extends DialogBase { 9 | @override 10 | bool get defaultValue => false; 11 | 12 | Future show(String header, String body, String confirmText, 13 | String declineText) async { 14 | return showInternally(AlertDialog( 15 | title: Text( 16 | header, 17 | style: textTheme.headline5, 18 | ), 19 | content: Text(body, 20 | style: textTheme.subtitle1, 21 | textAlign: TextAlign.start), 22 | actions: [ 23 | if (declineText?.isNotEmpty ?? false) 24 | FlatButton( 25 | onPressed: () => dismissDialog(false), 26 | child: Text( 27 | declineText, 28 | style: textTheme.subtitle1, 29 | ), 30 | ), 31 | FlatButton( 32 | onPressed: () => dismissDialog(false), 33 | child: Text( 34 | confirmText, 35 | style: textTheme.subtitle1, 36 | ), 37 | ), 38 | ], 39 | )); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/dialog/dialog_base.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | abstract class DialogBase { 8 | Completer _completer; 9 | 10 | T get defaultValue; 11 | 12 | @protected 13 | Future showInternally(Widget body) { 14 | _completer = Completer(); 15 | _showDialog(body); 16 | return _completer.future; 17 | } 18 | 19 | @protected 20 | void _showDialog(Widget body) { 21 | Get.dialog( 22 | WillPopScope( 23 | onWillPop: () { 24 | dismissDialog(defaultValue); 25 | return Future.value(false); 26 | }, 27 | child: body), 28 | barrierDismissible: true); 29 | } 30 | 31 | @protected 32 | void dismissDialog(T result) { 33 | Get.close(1); 34 | _trySetResult(result); 35 | } 36 | 37 | void _trySetResult(T result) { 38 | if (_completer != null) { 39 | _completer.complete(result); 40 | _completer = null; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/dialog/dialog_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/app_services/dialog/confirmation_dialog.dart'; 2 | import 'package:ecommers/shared/dependency_service.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | 5 | import 'confirm_phone_registration.dart'; 6 | 7 | class DialogService { 8 | Future showDialog( 9 | {@required String header, 10 | @required String body, 11 | @required String confirmText, 12 | String declineText}) { 13 | return ConfirmationDialog().show(header, body, confirmText, declineText); 14 | } 15 | 16 | Future confirmPhoneRegistration() { 17 | return ConfirmPhoneRegistration().showDialog(); 18 | } 19 | 20 | Future somethingWentWrong() { 21 | return showDialog( 22 | header: localization.something_went_wrongTitle, 23 | body: localization.something_went_wrongDescription, 24 | confirmText: localization.something_went_wrongPrimary_button); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/index.dart: -------------------------------------------------------------------------------- 1 | export 'app_service.dart'; 2 | export 'auth_response.dart'; 3 | export 'authorization_service.dart'; 4 | export 'category_service.dart'; 5 | export 'note_service.dart'; 6 | export 'paginator.dart'; 7 | export 'payment_method_service.dart'; 8 | export 'product_service.dart'; 9 | export 'profile_service.dart'; 10 | export 'shipping_address_service.dart'; -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/note_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/data_models/index.dart'; 2 | import 'package:ecommers/shared/dependency_service.dart'; 3 | 4 | class NoteService { 5 | Future> fetchLatestNotes() async => 6 | appService.fetchData(apiService.notes); 7 | } 8 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/paginator.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/data_models/index.dart'; 2 | 3 | class Paginator { 4 | static const int _pageSize = 20; 5 | 6 | int _currentPosition = 0; 7 | bool _hasMore = true; 8 | 9 | int get currentPosition => _currentPosition; 10 | bool get hasMore => _hasMore; 11 | 12 | Future> loadNextPage( 13 | Future> Function(int, int) request) async { 14 | final List portion = 15 | await request(currentPosition, currentPosition + _pageSize); 16 | 17 | if (portion == null || portion.length < _pageSize) { 18 | _hasMore = false; 19 | } else { 20 | _currentPosition += _pageSize; 21 | } 22 | 23 | return portion ?? []; 24 | } 25 | 26 | void reset() { 27 | _hasMore = true; 28 | _currentPosition = 0; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/payment_method_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/payment_method_model.dart'; 2 | import 'package:ecommers/shared/dependency_service.dart'; 3 | import 'package:stripe_payment/stripe_payment.dart'; 4 | 5 | class PaymentMethodService { 6 | static const String testPublishableKey = 7 | 'pk_test_O4MySLvZlQMSIVMEJPCQjbIv00CnR4Bawc'; 8 | static const String testMerchantId = 'Test'; 9 | static const String testandroidPayMode = 'test'; 10 | 11 | PaymentMethodService() { 12 | _initialize(); 13 | } 14 | 15 | Future _initialize() async { 16 | StripePayment.setOptions(StripeOptions( 17 | publishableKey: testPublishableKey, 18 | merchantId: testMerchantId, 19 | androidPayMode: testandroidPayMode, 20 | )); 21 | } 22 | 23 | Future> getPaymentMethods() async { 24 | return paymentMethodRepository.getAllOPaymentMethods(); 25 | } 26 | 27 | Future createPyamentMethod(CreditCard card) async { 28 | try { 29 | final paymentMethod = await StripePayment.createPaymentMethod( 30 | PaymentMethodRequest(card: card), 31 | ); 32 | final paymentMethodModel = 33 | PaymentMethodModel.fromStripePaymentMethod(paymentMethod); 34 | 35 | await paymentMethodRepository.add(paymentMethodModel); 36 | 37 | return paymentMethodModel; 38 | } catch (ex) { 39 | return null; 40 | } 41 | } 42 | 43 | Future removePaymentMethod(PaymentMethodModel paymentMethodModel) async { 44 | return paymentMethodRepository.remove(paymentMethodModel); 45 | } 46 | 47 | Future editPaymentMethod(PaymentMethodModel paymentMethodModel) async { 48 | return paymentMethodRepository.edit(paymentMethodModel); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/product_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/shared/dependency_service.dart'; 2 | import 'package:enum_to_string/enum_to_string.dart'; 3 | 4 | import 'package:ecommers/core/common/index.dart'; 5 | import 'package:ecommers/core/models/data_models/index.dart'; 6 | import 'package:ecommers/core/models/sort_type.dart'; 7 | 8 | class ProductService { 9 | Future> fetchProducts({ 10 | Categories category, 11 | String subCategory, 12 | int from, 13 | int to, 14 | String searchQuery, 15 | SortType sortType, 16 | }) async { 17 | final response = await apiService.products( 18 | category: EnumToString.parse(category), 19 | subCategory: subCategory, 20 | from: from, 21 | to: to, 22 | searchQuery: searchQuery, 23 | sortType: EnumToString.parse(sortType), 24 | ); 25 | 26 | if (response.isSuccessful) { 27 | return response.body; 28 | } 29 | 30 | return null; 31 | } 32 | 33 | Future> fetchLatestProducts(int from, int to) async { 34 | final response = await apiService.productsLatest(from, to); 35 | 36 | if (response.isSuccessful) { 37 | return response.body; 38 | } 39 | 40 | return null; 41 | } 42 | 43 | Future> fetchRecentProducts() async => 44 | appService.fetchData(apiService.productsRecent); 45 | 46 | Future recentProductsDelete() async { 47 | final response = await apiService.productsRecentDelete(); 48 | 49 | return response.isSuccessful; 50 | } 51 | 52 | Future> fetchRecommendedProducts() async => 53 | appService.fetchData(apiService.productRecommended); 54 | 55 | Future trySaveRecentProduct(Map product) async { 56 | final response = await apiService.productsRecentPost(product); 57 | return response.isSuccessful; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/profile_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_auth/firebase_auth.dart'; 2 | 3 | class ProfileService { 4 | FirebaseUser _user; 5 | FirebaseUser get user => _user; 6 | 7 | Future updateUserInfo() async { 8 | _user = await FirebaseAuth.instance.currentUser(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ecommers/lib/core/app_services/shipping_address_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/index.dart'; 2 | import 'package:ecommers/shared/dependency_service.dart'; 3 | import 'package:uuid/uuid.dart'; 4 | 5 | class ShippingAddressService { 6 | Future> getShippingAddresses() async { 7 | return shippingAddressRepository.getAllShippingAdderess(); 8 | } 9 | 10 | Future> getSelectedShippingAddress() async { 11 | return shippingAddressRepository.getSelectedShippingAddress(); 12 | } 13 | 14 | Future addSelectedShippingAddress(ShippingAddressModel item) async { 15 | return shippingAddressRepository.addSelectedShippingAddress(item); 16 | } 17 | 18 | Future updateSelectedShippingAddress(ShippingAddressModel item) async { 19 | return shippingAddressRepository.updateSelectedShippingAddress(item); 20 | } 21 | 22 | Future removeSelectedShippingAddress(ShippingAddressModel item) async { 23 | return shippingAddressRepository.removeSelectedShippingAddress(item); 24 | } 25 | 26 | Future createShippingAddress( 27 | ShippingAddressModel shippingAddressModel) async { 28 | try { 29 | final uuid = Uuid(); 30 | shippingAddressModel.id = uuid.v1(); 31 | await shippingAddressRepository.add( 32 | shippingAddressModel, 33 | ); 34 | 35 | return shippingAddressModel; 36 | } catch (ex) { 37 | logger.ex(ex); 38 | } 39 | } 40 | 41 | Future removeShippingAddresses( 42 | ShippingAddressModel shippingAddressModel) async { 43 | return shippingAddressRepository.remove(shippingAddressModel); 44 | } 45 | 46 | Future editShippingAddresses( 47 | ShippingAddressModel shippingAddressModel) async { 48 | return shippingAddressRepository.edit(shippingAddressModel); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ecommers/lib/core/cache/index.dart: -------------------------------------------------------------------------------- 1 | export 'cache_database.dart'; 2 | -------------------------------------------------------------------------------- /ecommers/lib/core/common/api_defines.dart: -------------------------------------------------------------------------------- 1 | class ApiDefines { 2 | static const String login = '/login'; 3 | static const String auth = '/auth'; 4 | 5 | static const String products = '/products'; 6 | static const String productsLatest = '/products/latest'; 7 | static const String productsRecent = '/products/recent'; 8 | static const String productsRecommended = '/products/recommended'; 9 | 10 | static const String categories = '/categories'; 11 | 12 | static const String notes = '/notes'; 13 | 14 | static const String profile = '/profile'; 15 | static const String profileOrders = '/profile/orders'; 16 | static const String profilePendingShipment = '/profile/pending/shipment'; 17 | static const String profilePendingPayment = '/profile/pending/payment'; 18 | } -------------------------------------------------------------------------------- /ecommers/lib/core/common/api_query_params.dart: -------------------------------------------------------------------------------- 1 | class ApiQueryParams { 2 | static const String category = 'category'; 3 | static const String subCategory = 'subCategory'; 4 | static const String rangeFrom = 'from'; 5 | static const String rangeTo = 'to'; 6 | static const String searchQuery = 'searchQuery'; 7 | static const String sortType = 'sortType'; 8 | } -------------------------------------------------------------------------------- /ecommers/lib/core/common/cache_defines.dart: -------------------------------------------------------------------------------- 1 | class CacheDefines { 2 | static const String categories = 'categories'; 3 | static const String latestProducts = 'latestProducts'; 4 | static const String paymentMethods = 'paymentMethods'; 5 | static const String shippingAddress = 'shippingAddress'; 6 | static const String orders = 'orders'; 7 | static const String selectedShippingAddressId = 'selectedShippingAddressId'; 8 | } 9 | -------------------------------------------------------------------------------- /ecommers/lib/core/common/categories.dart: -------------------------------------------------------------------------------- 1 | enum Categories { 2 | apparel, 3 | beauty, 4 | electronics, 5 | furniture, 6 | home, 7 | shoes, 8 | stationary, 9 | seeAll 10 | } 11 | -------------------------------------------------------------------------------- /ecommers/lib/core/common/file_manager.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | 3 | class FileManager { 4 | static const String jsonPath = 'lib/web_server/data/'; 5 | 6 | static Future readJson(String fileName) async { 7 | final fullPath = jsonPath + fileName; 8 | return rootBundle.loadString(fullPath); 9 | } 10 | } -------------------------------------------------------------------------------- /ecommers/lib/core/common/index.dart: -------------------------------------------------------------------------------- 1 | export 'api_defines.dart'; 2 | export 'api_query_params.dart'; 3 | export 'cache_defines.dart'; 4 | export 'categories.dart'; 5 | export 'file_manager.dart'; 6 | export 'json_serializable_converter.dart'; 7 | export 'pages.dart'; 8 | export 'user_validator.dart'; 9 | -------------------------------------------------------------------------------- /ecommers/lib/core/common/json_serializable_converter.dart: -------------------------------------------------------------------------------- 1 | import 'package:chopper/chopper.dart'; 2 | 3 | typedef JsonFactory = T Function(Map json); 4 | 5 | class JsonSerializableConverter extends JsonConverter { 6 | final Map _factories; 7 | 8 | const JsonSerializableConverter({Map factories}) 9 | : _factories = factories; 10 | 11 | T _decodeMap(Map values) { 12 | final jsonFactory = _factories[T]; 13 | if (jsonFactory == null || jsonFactory is! JsonFactory) { 14 | return throw 'not found factory'; 15 | } 16 | 17 | return jsonFactory(values) as T; 18 | } 19 | 20 | List _decodeList(List values) => 21 | values.where((v) => v != null).map((v) => _decode(v) as T).toList(); 22 | 23 | dynamic _decode(entity) { 24 | if (entity is Iterable) { 25 | return _decodeList(entity as List); 26 | } 27 | 28 | if (entity is Map) { 29 | return _decodeMap(entity as Map); 30 | } 31 | 32 | return entity; 33 | } 34 | 35 | @override 36 | Response convertResponse(Response response) { 37 | final jsonRes = super.convertResponse(response); 38 | 39 | return jsonRes.copyWith( 40 | body: _decode(jsonRes.body) as ResultType); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ecommers/lib/core/common/pages.dart: -------------------------------------------------------------------------------- 1 | enum Pages { 2 | shell, 3 | home, 4 | search, 5 | cart, 6 | profile, 7 | profileEdit, 8 | more, 9 | categories, 10 | productsGrid, 11 | authorization, 12 | checkout, 13 | success, 14 | product, 15 | notifications, 16 | note, 17 | paymentMethod, 18 | addPaymentMethod, 19 | shippingAddress, 20 | addShippingAddress, 21 | } 22 | -------------------------------------------------------------------------------- /ecommers/lib/core/common/user_validator.dart: -------------------------------------------------------------------------------- 1 | class UserValidator { 2 | static const int _minPasswordLength = 4; 3 | static const _emailPattern = 4 | r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+"; 5 | 6 | static bool isEmail(String email) { 7 | final regexp = RegExp(_emailPattern); 8 | 9 | return regexp.hasMatch(email); 10 | } 11 | 12 | static bool isPhoneNumber(String phone) { 13 | const _phoneNumber = r'^[0-9]{12}$'; 14 | final regexp = RegExp(_phoneNumber); 15 | 16 | return regexp.hasMatch(phone); 17 | } 18 | 19 | static bool isPasswordValid(String password) { 20 | return password.length >= _minPasswordLength; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ecommers/lib/core/common/validator/index.dart: -------------------------------------------------------------------------------- 1 | export 'shipping_address_validator.dart'; -------------------------------------------------------------------------------- /ecommers/lib/core/common/validator/shipping_address_validator.dart: -------------------------------------------------------------------------------- 1 | class ShippingValidator{ 2 | 3 | static bool isFullNameValid(String fullName) => 4 | fullName != null && fullName.length > 3; 5 | 6 | static bool isAddressValid(String address) => 7 | address != null && address.length > 2; 8 | 9 | static bool isCityValid(String city) => 10 | city != null && city.length > 2; 11 | 12 | static bool isStateValid(String state) => 13 | state != null && state.length > 3; 14 | 15 | static bool isZipCodeValid(String zipCode) => 16 | zipCode != null && zipCode.length > 2; 17 | 18 | static bool isCountryValid(String country) => 19 | country != null && country.length > 3; 20 | } -------------------------------------------------------------------------------- /ecommers/lib/core/mixins/busy_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | mixin BusyNotifier on ChangeNotifier { 4 | bool _hasDisposed = false; 5 | bool _isBusy = false; 6 | 7 | bool get isBusy => _isBusy; 8 | 9 | set isBusy(bool isBusy) { 10 | _isBusy = isBusy; 11 | 12 | if (!_hasDisposed) notifyListeners(); 13 | } 14 | 15 | @override 16 | void dispose() { 17 | _hasDisposed = true; 18 | super.dispose(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ecommers/lib/core/mixins/index.dart: -------------------------------------------------------------------------------- 1 | export 'busy_notifier.dart'; 2 | export 'items_loading_notifier.dart'; 3 | -------------------------------------------------------------------------------- /ecommers/lib/core/mixins/items_loading_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | import 'package:ecommers/core/app_services/index.dart'; 6 | import 'package:ecommers/shared/dependency_service.dart'; 7 | 8 | mixin ItemsLoadingNotifier on ChangeNotifier { 9 | @protected 10 | final Paginator paginator = createPaginator(); 11 | 12 | bool _hasDisposed = false; 13 | bool _isItemsLoading = false; 14 | 15 | bool get isItemsLoading => _isItemsLoading; 16 | bool get hasMoreItems => paginator.hasMore; 17 | 18 | set isItemsLoading(bool isitemsLoading) { 19 | _isItemsLoading = isitemsLoading; 20 | 21 | if (!_hasDisposed) notifyListeners(); 22 | } 23 | 24 | FutureOr loadMoreProducts() {} 25 | 26 | @override 27 | void dispose() { 28 | _hasDisposed = true; 29 | super.dispose(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/auth_rich_text_span_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class AuthRichTextSpanModel { 4 | final String text; 5 | final bool isTappable; 6 | final Function() onTap; 7 | final UniqueKey id = UniqueKey(); 8 | 9 | AuthRichTextSpanModel({ 10 | this.text = '', 11 | this.isTappable = false, 12 | this.onTap, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/cache_wrappers/categories_cache_wrapper.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/data_models/index.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'categories_cache_wrapper.g.dart'; 5 | 6 | @JsonSerializable() 7 | class CategoriesCacheWrapper { 8 | @JsonKey(name: 'key') 9 | final String key; 10 | @JsonKey(name: 'lastUpdatedDate') 11 | final DateTime lastUpdatedDate; 12 | @JsonKey(name: 'categories') 13 | final List categories; 14 | 15 | CategoriesCacheWrapper(this.key, this.lastUpdatedDate, this.categories); 16 | 17 | static const fromJson = _$CategoriesCacheWrapperFromJson; 18 | 19 | Map toJson() => _$CategoriesCacheWrapperToJson(this); 20 | } -------------------------------------------------------------------------------- /ecommers/lib/core/models/cache_wrappers/index.dart: -------------------------------------------------------------------------------- 1 | export 'categories_cache_wrapper.dart'; -------------------------------------------------------------------------------- /ecommers/lib/core/models/data_models/category.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/common/categories.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'category.g.dart'; 5 | 6 | @JsonSerializable() 7 | class Category { 8 | final int id; 9 | final String title; 10 | final Categories type; 11 | @JsonKey(name: 'color1') 12 | final String gradientColor1; 13 | @JsonKey(name: 'color2') 14 | final String gradientColor2; 15 | final String shadowColor; 16 | final List subCategories; 17 | 18 | Category({ 19 | this.id, 20 | this.title, 21 | this.subCategories, 22 | this.type, 23 | this.gradientColor1, 24 | this.gradientColor2, 25 | this.shadowColor, 26 | }); 27 | 28 | static const fromJsonFactory = _$CategoryFromJson; 29 | 30 | factory Category.fromJson(Map json) => 31 | _$CategoryFromJson(json); 32 | 33 | Map toJson() => _$CategoryToJson(this); 34 | } 35 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/data_models/index.dart: -------------------------------------------------------------------------------- 1 | export 'category.dart'; 2 | export 'note.dart'; 3 | export 'product.dart'; 4 | export 'product_details.dart'; 5 | export 'product_model.dart'; 6 | export 'product_review.dart'; 7 | export 'user.dart'; -------------------------------------------------------------------------------- /ecommers/lib/core/models/data_models/note.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'note.g.dart'; 4 | 5 | @JsonSerializable() 6 | class Note { 7 | final int id; 8 | final String title; 9 | final String imageUrl; 10 | final String commandText; 11 | final String description; 12 | final String shortDescription; 13 | 14 | Note( 15 | this.id, 16 | this.title, 17 | this.imageUrl, 18 | this.commandText, 19 | this.description, 20 | this.shortDescription, 21 | ); 22 | 23 | static const fromJsonFactory = _$NoteFromJson; 24 | 25 | factory Note.fromJson(Map json) => _$NoteFromJson(json); 26 | 27 | Map toJson() => _$NoteToJson(this); 28 | } 29 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/data_models/product.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | import 'product_color.dart'; 4 | import 'product_details.dart'; 5 | import 'product_model.dart'; 6 | import 'product_review.dart'; 7 | 8 | part 'product.g.dart'; 9 | 10 | @JsonSerializable() 11 | class Product { 12 | final int id; 13 | final String gender; 14 | final String category; 15 | final String subCategory; 16 | final String title; 17 | final double price; 18 | final ProductColor baseColor; 19 | final int catalogAddDate; 20 | final String previewImage; 21 | 22 | @JsonKey(name: 'styleImages') 23 | final List images; 24 | 25 | final double rate; 26 | final List models; 27 | final ProductDetails details; 28 | final List reviews; 29 | 30 | Product( 31 | this.id, 32 | this.gender, 33 | this.category, 34 | this.title, 35 | this.price, 36 | this.baseColor, 37 | this.images, 38 | this.rate, 39 | this.models, 40 | this.details, 41 | this.reviews, 42 | this.subCategory, 43 | this.catalogAddDate, 44 | this.previewImage, 45 | ); 46 | 47 | static const fromJsonFactory = _$ProductFromJson; 48 | 49 | factory Product.fromJson(Map json) => 50 | _$ProductFromJson(json); 51 | 52 | Map toJson() => _$ProductToJson(this); 53 | } 54 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/data_models/product_color.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'product_color.g.dart'; 4 | 5 | @JsonSerializable() 6 | class ProductColor { 7 | final String title; 8 | final int argb; 9 | 10 | ProductColor( 11 | this.title, 12 | this.argb 13 | ); 14 | 15 | static const fromJsonFactory = _$ProductColorFromJson; 16 | 17 | factory ProductColor.fromJson(Map json) => 18 | _$ProductColorFromJson(json); 19 | 20 | Map toJson() => _$ProductColorToJson(this); 21 | } 22 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/data_models/product_details.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'product_details.g.dart'; 4 | 5 | @JsonSerializable() 6 | class ProductDetails { 7 | final String brand; 8 | final String condition; 9 | final String category; 10 | final String material; 11 | final String fitting; 12 | 13 | ProductDetails( 14 | this.brand, 15 | this.condition, 16 | this.category, 17 | this.material, 18 | this.fitting, 19 | ); 20 | 21 | static const fromJsonFactory = _$ProductDetailsFromJson; 22 | 23 | factory ProductDetails.fromJson(Map json) => 24 | _$ProductDetailsFromJson(json); 25 | 26 | Map toJson() => _$ProductDetailsToJson(this); 27 | } 28 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/data_models/product_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | import 'product_color.dart'; 4 | 5 | part 'product_model.g.dart'; 6 | 7 | @JsonSerializable() 8 | class ProductModel { 9 | final String size; 10 | final ProductColor color; 11 | final int skuId; 12 | final List imageUrls; 13 | final bool isAvailable; 14 | final int totalCount; 15 | 16 | ProductModel({ 17 | this.size, 18 | this.color, 19 | this.skuId, 20 | this.imageUrls, 21 | this.isAvailable, 22 | this.totalCount, 23 | }); 24 | 25 | static const fromJsonFactory = _$ProductModelFromJson; 26 | 27 | factory ProductModel.fromJson(Map json) => 28 | _$ProductModelFromJson(json); 29 | 30 | Map toJson() => _$ProductModelToJson(this); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/data_models/product_review.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | import 'user.dart'; 4 | 5 | part 'product_review.g.dart'; 6 | 7 | @JsonSerializable() 8 | class ProductReview { 9 | final User user; 10 | final DateTime date; 11 | final String comment; 12 | final List imageUrls; 13 | final int rate; 14 | 15 | ProductReview( 16 | this.user, 17 | this.date, 18 | this.comment, 19 | this.imageUrls, 20 | this.rate, 21 | ); 22 | 23 | static const fromJsonFactory = _$ProductReviewFromJson; 24 | 25 | factory ProductReview.fromJson(Map json) => 26 | _$ProductReviewFromJson(json); 27 | 28 | Map toJson() => _$ProductReviewToJson(this); 29 | } 30 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/data_models/user.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'user.g.dart'; 4 | 5 | @JsonSerializable() 6 | class User { 7 | final String username; 8 | final String email; 9 | final String password; 10 | final String firstName; 11 | final String lastName; 12 | final String avatar; 13 | final String address; 14 | 15 | User( 16 | this.username, 17 | this.email, 18 | this.password, 19 | this.firstName, 20 | this.lastName, 21 | this.avatar, 22 | this.address, 23 | ); 24 | 25 | static const fromJsonFactory = _$UserFromJson; 26 | 27 | factory User.fromJson(Map json) => _$UserFromJson(json); 28 | 29 | Map toJson() => _$UserToJson(this); 30 | } 31 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/index.dart: -------------------------------------------------------------------------------- 1 | export 'auth_rich_text_span_model.dart'; 2 | export 'item_base.dart'; 3 | export 'login_model.dart'; 4 | export 'notification_model.dart'; 5 | export 'order_model.dart'; 6 | export 'page_arguments.dart'; 7 | export 'payment_method_model.dart'; 8 | export 'product_color_model.dart'; 9 | export 'product_size_model.dart'; 10 | export 'product_skuid_model.dart'; 11 | export 'sort_type.dart'; 12 | export 'shipping_address_model.dart'; 13 | export 'user_model.dart'; 14 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/item_base.dart: -------------------------------------------------------------------------------- 1 | class ItemBase { 2 | final dynamic id; 3 | 4 | ItemBase(this.id); 5 | } -------------------------------------------------------------------------------- /ecommers/lib/core/models/login_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'login_model.g.dart'; 4 | 5 | @JsonSerializable() 6 | class LoginModel { 7 | @JsonKey(name: 'access_token') 8 | final String token; 9 | 10 | @JsonKey(name: 'refresh_token') 11 | final String refreshToken; 12 | 13 | @JsonKey(name: 'expiration_date') 14 | final String expirationDate; 15 | 16 | LoginModel(this.token, this.refreshToken, this.expirationDate); 17 | 18 | static const fromJsonFactory = _$LoginModelFromJson; 19 | 20 | Map toJson() => _$LoginModelToJson(this); 21 | } 22 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/notification_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | class NotificationModel { 4 | final String orderNumber; 5 | final String notificationUsualText; 6 | final String statusText; 7 | final bool isCheckedItem; 8 | final Color backgroundColor; 9 | final Color shadowColor; 10 | final String imgPath; 11 | final DateTime day; 12 | 13 | NotificationModel({ 14 | this.orderNumber, 15 | this.notificationUsualText, 16 | this.isCheckedItem, 17 | this.statusText, 18 | this.backgroundColor, 19 | this.shadowColor, 20 | this.imgPath, 21 | this.day, 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/order_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/index.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'data_models/index.dart'; 4 | 5 | part 'order_model.g.dart'; 6 | 7 | @JsonSerializable() 8 | class OrderModel implements ItemBase{ 9 | @override 10 | final int id; 11 | final Product product; 12 | final String characteristics; 13 | int count; 14 | 15 | OrderModel({ 16 | this.id, 17 | this.product, 18 | this.characteristics, 19 | this.count = 1, 20 | }); 21 | 22 | static const fromJson = _$OrderModelFromJson; 23 | 24 | factory OrderModel.fromProduct({Product product, String size, String color}) { 25 | return OrderModel( 26 | id: product.id, 27 | product: product, 28 | characteristics: '$size, $color', 29 | count: 1, 30 | ); 31 | } 32 | 33 | Map toJson() => _$OrderModelToJson(this); 34 | } 35 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/page_arguments.dart: -------------------------------------------------------------------------------- 1 | class PageArguments { 2 | final Object arg1; 3 | final Object arg2; 4 | 5 | PageArguments({this.arg1, this.arg2}); 6 | } 7 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/payment_method_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/index.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:stripe_payment/stripe_payment.dart'; 4 | 5 | part 'payment_method_model.g.dart'; 6 | 7 | @JsonSerializable() 8 | class PaymentMethodModel implements ItemBase { 9 | @override 10 | final String id; 11 | final String cardCountry; 12 | final int cardExpMonth; 13 | final int cardExpYear; 14 | final String cardNumberLast4; 15 | final String cardBrand; 16 | bool isSelected; 17 | 18 | PaymentMethodModel({ 19 | this.id, 20 | this.cardCountry, 21 | this.cardExpMonth, 22 | this.cardExpYear, 23 | this.cardNumberLast4, 24 | this.cardBrand, 25 | this.isSelected = false, 26 | }); 27 | 28 | factory PaymentMethodModel.fromStripePaymentMethod(PaymentMethod paymentMethod) { 29 | return PaymentMethodModel( 30 | id: paymentMethod.id, 31 | isSelected: false, 32 | cardBrand: paymentMethod.card.brand, 33 | cardCountry: paymentMethod.card.country, 34 | cardExpMonth: paymentMethod.card.expMonth, 35 | cardExpYear: paymentMethod.card.expYear, 36 | cardNumberLast4: paymentMethod.card.last4, 37 | ); 38 | } 39 | 40 | static const fromJson = _$PaymentMethodModelFromJson; 41 | 42 | Map toJson() => _$PaymentMethodModelToJson(this); 43 | } 44 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/product_color_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/ui/widgets/right_menu_bar/models/index.dart'; 2 | import 'package:meta/meta.dart'; 3 | 4 | class ProductColorModel { 5 | bool isSelected; 6 | final int color; 7 | final String title; 8 | final List images; 9 | 10 | ProductColorModel({ 11 | @required this.color, 12 | @required this.images, 13 | this.isSelected = false, 14 | this.title, 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/product_size_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | 3 | class ProductSizeModel { 4 | bool isSelected; 5 | final String size; 6 | 7 | ProductSizeModel({ 8 | @required this.size, 9 | this.isSelected = false, 10 | }); 11 | } -------------------------------------------------------------------------------- /ecommers/lib/core/models/product_skuid_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class ProductSkuIdModel { 4 | final int color; 5 | final String size; 6 | 7 | ProductSkuIdModel({ 8 | @required this.size, 9 | @required this.color, 10 | }); 11 | } -------------------------------------------------------------------------------- /ecommers/lib/core/models/shipping_address_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/index.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | 4 | part 'shipping_address_model.g.dart'; 5 | 6 | @JsonSerializable() 7 | class ShippingAddressModel implements ItemBase { 8 | @override 9 | String id; 10 | String fullName; 11 | String address; 12 | String city; 13 | String state; 14 | String zipCode; 15 | String country; 16 | 17 | ShippingAddressModel({ 18 | this.id, 19 | this.fullName, 20 | this.address, 21 | this.city, 22 | this.state, 23 | this.zipCode, 24 | this.country, 25 | }); 26 | 27 | static const fromJson = _$ShippingAddressModelFromJson; 28 | 29 | Map toJson() => _$ShippingAddressModelToJson(this); 30 | } 31 | -------------------------------------------------------------------------------- /ecommers/lib/core/models/sort_type.dart: -------------------------------------------------------------------------------- 1 | enum SortType { 2 | rate, 3 | cost, 4 | costDesc 5 | } -------------------------------------------------------------------------------- /ecommers/lib/core/models/user_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'user_model.g.dart'; 4 | 5 | @JsonSerializable() 6 | class UserModel { 7 | final String username; 8 | 9 | final String email; 10 | 11 | UserModel(this.username, this.email); 12 | } -------------------------------------------------------------------------------- /ecommers/lib/core/provider_models/auth/forgot_password_provider_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/mixins/index.dart'; 2 | import 'package:ecommers/shared/dependency_service.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class ForgotPasswordProviderModel extends ChangeNotifier with BusyNotifier { 6 | Future resetPassword(String email) async { 7 | isBusy = true; 8 | final result = await authorizationService.restorePassword(email); 9 | isBusy = false; 10 | 11 | if (result) { 12 | dialogService.showDialog( 13 | header: localization.password_restoration_dialogTitle, 14 | body: localization.password_restoration_dialogDescription, 15 | confirmText: localization.password_restoration_dialogPrimary_button); 16 | } else { 17 | dialogService.somethingWentWrong(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ecommers/lib/core/provider_models/base_provider_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/mixins/busy_notifier.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class BusyProviderModel extends ChangeNotifier with BusyNotifier {} 5 | -------------------------------------------------------------------------------- /ecommers/lib/core/provider_models/categories_provider_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/mixins/index.dart'; 2 | import 'package:ecommers/core/models/data_models/category.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class CategoriesProviderModel extends ChangeNotifier with BusyNotifier { 6 | final List categoryList; 7 | int _selectedCategoryIndex = 0; 8 | 9 | Category get selectedCategory => categoryList[_selectedCategoryIndex]; 10 | 11 | int get selectedCategoryIndex => _selectedCategoryIndex; 12 | set selectedCategoryIndex(int index) { 13 | if (selectedCategoryIndex == index) return; 14 | 15 | _selectedCategoryIndex = index; 16 | 17 | notifyListeners(); 18 | } 19 | 20 | CategoriesProviderModel(this.categoryList); 21 | } 22 | -------------------------------------------------------------------------------- /ecommers/lib/core/provider_models/home_provider_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:ecommers/core/mixins/index.dart'; 4 | import 'package:ecommers/shared/dependency_service.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | import 'package:ecommers/core/mixins/items_loading_notifier.dart'; 8 | import 'package:ecommers/core/models/data_models/index.dart'; 9 | 10 | class HomeProviderModel extends ChangeNotifier 11 | with ItemsLoadingNotifier, BusyNotifier { 12 | List _categoryList; 13 | List _productsLatest; 14 | List _notesLatest; 15 | 16 | List get categoryList => _categoryList; 17 | List get productsLatest => _productsLatest; 18 | List get notesLatest => _notesLatest; 19 | 20 | HomeProviderModel() { 21 | fetchAllData(); 22 | } 23 | 24 | Future fetchAllData() async { 25 | isBusy = true; 26 | 27 | await Future.wait({ 28 | _fetchCategories(), 29 | _fetchLatestProducts(), 30 | _fetchLatestNotes(), 31 | }); 32 | 33 | isBusy = false; 34 | } 35 | 36 | Future _fetchCategories() async { 37 | _categoryList = await categoryService.fetchCategoryList(); 38 | } 39 | 40 | Future _fetchLatestProducts() async { 41 | _productsLatest = 42 | await paginator.loadNextPage(productService.fetchLatestProducts); 43 | } 44 | 45 | Future _fetchLatestNotes() async { 46 | _notesLatest = await noteService.fetchLatestNotes(); 47 | } 48 | 49 | @override 50 | FutureOr loadMoreProducts() async { 51 | isItemsLoading = true; 52 | 53 | final products = 54 | await paginator.loadNextPage(productService.fetchLatestProducts); 55 | 56 | _productsLatest.addAll(products); 57 | 58 | isItemsLoading = false; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ecommers/lib/core/provider_models/index.dart: -------------------------------------------------------------------------------- 1 | export 'base_provider_model.dart'; 2 | export 'cart_provider.dart'; 3 | export 'categories_provider_model.dart'; 4 | export 'home_provider_model.dart'; 5 | export 'more_provider_model.dart'; 6 | export 'payment_method_provider_model.dart'; 7 | export 'product_page_provider_model.dart'; 8 | export 'product_tab_provider_model.dart'; 9 | export 'products_grid_provder_model.dart'; 10 | export 'profile_provider_model.dart'; 11 | export 'search_page_provider_model.dart'; 12 | export 'search_query_provider_model.dart'; 13 | export 'shell_provider_model.dart'; 14 | export 'shipping_address_provider_model.dart'; 15 | -------------------------------------------------------------------------------- /ecommers/lib/core/provider_models/more_provider_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/common/index.dart'; 2 | import 'package:ecommers/core/mixins/index.dart'; 3 | import 'package:ecommers/shared/dependency_service.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class MoreProviderModel extends ChangeNotifier with BusyNotifier { 7 | 8 | Future logOutPressHandler() async { 9 | await cacheDatabase.dropDataBase(); 10 | authorizationService.logOut(); 11 | await navigationService.navigateWithReplacementTo(Pages.authorization); 12 | } 13 | } -------------------------------------------------------------------------------- /ecommers/lib/core/provider_models/product_tab_provider_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/mixins/index.dart'; 2 | import 'package:ecommers/core/models/index.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | 5 | class ProductTabProviderModel extends ChangeNotifier with BusyNotifier { 6 | List _colors; 7 | List _sizes; 8 | 9 | List get sizes => _sizes; 10 | set sizes(List sizes) => _sizes = sizes ?? []; 11 | 12 | List get colors => _colors; 13 | set colors(List colors) => _colors = colors ?? []; 14 | 15 | ProductTabProviderModel(this._colors, this._sizes); 16 | 17 | void selectSize(int index) { 18 | sizes.forEach(_unselectSizes); 19 | sizes[index].isSelected = true; 20 | 21 | notifyListeners(); 22 | } 23 | 24 | void selectColor(int index) { 25 | colors.forEach(_unselectColors); 26 | colors[index].isSelected = true; 27 | 28 | notifyListeners(); 29 | } 30 | 31 | void _unselectSizes(ProductSizeModel size) { 32 | size.isSelected = false; 33 | } 34 | 35 | void _unselectColors(ProductColorModel color) { 36 | color.isSelected = false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ecommers/lib/core/provider_models/profile_provider_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/mixins/busy_notifier.dart'; 2 | import 'package:ecommers/shared/dependency_service.dart'; 3 | import 'package:flutter/cupertino.dart'; 4 | 5 | class ProfileProviderModel extends ChangeNotifier with BusyNotifier { 6 | String get email => profileService.user.email; 7 | 8 | String get emailOrPhone => 9 | profileService.user.email ?? profileService.user.phoneNumber; 10 | 11 | String get name => profileService.user.displayName ?? emailOrPhone; 12 | 13 | String get phone => profileService.user.phoneNumber; 14 | 15 | Future saveChanges(String name) async { 16 | if (profileService.user.displayName != name) { 17 | isBusy = true; 18 | await authorizationService.updateUserName(name); 19 | await profileService.updateUserInfo(); 20 | isBusy = false; 21 | 22 | notifyListeners(); 23 | } 24 | 25 | navigationService.goBack(); 26 | } 27 | 28 | Future resetPassword(String email) async { 29 | isBusy = true; 30 | final result = await authorizationService.restorePassword(email); 31 | isBusy = false; 32 | 33 | if (result) { 34 | dialogService.showDialog( 35 | header: localization.password_reset_dialogTitle, 36 | body: localization.password_reset_dialogDescription, 37 | confirmText: localization.password_reset_dialogPrimary_button); 38 | } else { 39 | dialogService.somethingWentWrong(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ecommers/lib/core/provider_models/search_page_provider_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/mixins/index.dart'; 2 | import 'package:ecommers/core/models/data_models/index.dart'; 3 | import 'package:ecommers/shared/dependency_service.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class SearchPageProviderModel extends ChangeNotifier with BusyNotifier { 7 | List _recentProducts; 8 | List _recommendedProducts; 9 | 10 | List get recentProducts => _recentProducts; 11 | List get recommendedProducts => _recommendedProducts; 12 | 13 | SearchPageProviderModel() { 14 | fetchAllData(); 15 | } 16 | 17 | Future fetchAllData() async { 18 | isBusy = true; 19 | 20 | await Future.wait({ 21 | _fetchRecentProducts(), 22 | _fetchRecommendedProducts(), 23 | }); 24 | 25 | isBusy = false; 26 | } 27 | 28 | void clearRecentProducts() { 29 | productService.recentProductsDelete(); 30 | _recentProducts.clear(); 31 | notifyListeners(); 32 | } 33 | 34 | Future updateRecentProducts() async { 35 | isBusy = true; 36 | 37 | await _fetchRecentProducts(); 38 | 39 | isBusy = false; 40 | } 41 | 42 | Future refreshRecommendedProducts() async { 43 | isBusy = true; 44 | 45 | await _fetchRecommendedProducts(); 46 | notifyListeners(); 47 | 48 | isBusy = false; 49 | } 50 | 51 | Future _fetchRecentProducts() async { 52 | _recentProducts = await productService.fetchRecentProducts(); 53 | } 54 | 55 | Future _fetchRecommendedProducts() async { 56 | _recommendedProducts = await productService.fetchRecommendedProducts(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ecommers/lib/core/provider_models/search_query_provider_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SearchQueryProviderModel extends ChangeNotifier { 4 | String _searchQuery; 5 | 6 | String get searchQuery => _searchQuery; 7 | set searchQuery(String query) { 8 | if (_searchQuery == query) return; 9 | 10 | _searchQuery = query; 11 | 12 | notifyListeners(); 13 | } 14 | } -------------------------------------------------------------------------------- /ecommers/lib/core/provider_models/shell_provider_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/common/index.dart'; 2 | import 'package:ecommers/core/mixins/index.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class ShellProviderModel extends ChangeNotifier with BusyNotifier { 6 | final List pages = [ 7 | Pages.home, 8 | Pages.search, 9 | Pages.cart, 10 | Pages.profile, 11 | Pages.more 12 | ]; 13 | 14 | int selectedItemIndex = 0; 15 | 16 | Pages get selectedPage => pages[selectedItemIndex]; 17 | 18 | void onTappedItem(int index) { 19 | selectedItemIndex = index; 20 | notifyListeners(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ecommers/lib/core/repositories/cart_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/common/index.dart'; 2 | import 'package:ecommers/core/models/index.dart'; 3 | import 'package:ecommers/core/repositories/index.dart'; 4 | import 'package:ecommers/shared/dependency_service.dart'; 5 | 6 | class CartRepository extends RepositoryBase { 7 | static const filterFieldOrderId = 'id'; 8 | CartRepository() 9 | : super( 10 | filterFieldForItem: filterFieldOrderId, 11 | repositoryKey: CacheDefines.orders, 12 | ); 13 | 14 | Future> getAllOrders() async { 15 | return cacheDatabase.getAll( 16 | repositoryKey, 17 | OrderModel.fromJson); 18 | 19 | } 20 | 21 | Future dropOrders() async { 22 | await cacheDatabase.dropData(repositoryKey); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ecommers/lib/core/repositories/index.dart: -------------------------------------------------------------------------------- 1 | export 'cart_repository.dart'; 2 | export 'category_data_repository.dart'; 3 | export 'payment_method_repository.dart'; 4 | export 'repository_base.dart'; 5 | export 'shipping_address_repository.dart'; -------------------------------------------------------------------------------- /ecommers/lib/core/repositories/payment_method_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/common/index.dart'; 2 | import 'package:ecommers/core/models/index.dart'; 3 | import 'package:ecommers/shared/dependency_service.dart'; 4 | import 'package:ecommers/core/repositories/index.dart'; 5 | 6 | class PaymentMethodRepository extends RepositoryBase { 7 | static const filterFieldId = 'id'; 8 | 9 | PaymentMethodRepository() 10 | : super( 11 | filterFieldForItem: filterFieldId, 12 | repositoryKey: CacheDefines.paymentMethods, 13 | ); 14 | 15 | Future> getAllOPaymentMethods() async { 16 | return cacheDatabase.getAll(repositoryKey, PaymentMethodModel.fromJson); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ecommers/lib/core/repositories/repository_base.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:ecommers/core/models/index.dart'; 3 | import 'package:ecommers/shared/dependency_service.dart'; 4 | 5 | class RepositoryBase { 6 | final String filterFieldForItem; 7 | final String repositoryKey; 8 | 9 | RepositoryBase({ 10 | this.filterFieldForItem, 11 | this.repositoryKey, 12 | }); 13 | 14 | Future edit(T item) async { 15 | return cacheDatabase.updateByEqualsFilter( 16 | repositoryKey, json.decode(json.encode(item)) as Map, { 17 | filterFieldForItem: item.id, 18 | }); 19 | } 20 | 21 | Future add(T item) async { 22 | return cacheDatabase.saveMap( 23 | repositoryKey, json.decode(json.encode(item)) as Map); 24 | } 25 | 26 | Future remove(T item) async { 27 | return cacheDatabase.deleteDataByFilter(repositoryKey, { 28 | filterFieldForItem: item.id, 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ecommers/lib/core/repositories/shipping_address_repository.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:ecommers/core/common/index.dart'; 4 | import 'package:ecommers/core/models/index.dart'; 5 | import 'package:ecommers/core/repositories/index.dart'; 6 | import 'package:ecommers/shared/dependency_service.dart'; 7 | 8 | class ShippingAddressRepository extends RepositoryBase { 9 | static const filterFieldId = 'id'; 10 | 11 | ShippingAddressRepository() 12 | : super( 13 | filterFieldForItem: filterFieldId, 14 | repositoryKey: CacheDefines.shippingAddress, 15 | ); 16 | 17 | Future> getSelectedShippingAddress() { 18 | return cacheDatabase.getAll( 19 | CacheDefines.selectedShippingAddressId, ShippingAddressModel.fromJson); 20 | } 21 | 22 | Future addSelectedShippingAddress(ShippingAddressModel item) { 23 | return cacheDatabase.saveMap(CacheDefines.selectedShippingAddressId, 24 | json.decode(json.encode(item)) as Map); 25 | } 26 | 27 | Future updateSelectedShippingAddress(ShippingAddressModel item) async { 28 | return cacheDatabase.updateByEqualsFilter( 29 | repositoryKey, json.decode(json.encode(item)) as Map, { 30 | filterFieldForItem: item.id, 31 | }); 32 | } 33 | 34 | Future removeSelectedShippingAddress(ShippingAddressModel item) { 35 | return cacheDatabase 36 | .deleteDataByFilter(CacheDefines.selectedShippingAddressId, { 37 | filterFieldForItem: item.id, 38 | }); 39 | } 40 | 41 | Future> getAllShippingAdderess() async { 42 | return cacheDatabase.getAll(repositoryKey, ShippingAddressModel.fromJson); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ecommers/lib/core/services/index.dart: -------------------------------------------------------------------------------- 1 | export 'api_service.dart'; 2 | export 'membership_service.dart'; 3 | -------------------------------------------------------------------------------- /ecommers/lib/data/repository/common.mappings.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/index.dart'; 2 | import 'package:firebase_auth/firebase_auth.dart'; 3 | 4 | extension AuthExt on AuthResult { 5 | LoginModel toLoginModel() { 6 | //firebase auth do not has tokens 7 | return LoginModel('token', 'refreshToken', 8 | DateTime.now().add(const Duration(days: 180)).toString()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ecommers/lib/data/result.dart: -------------------------------------------------------------------------------- 1 | class Result { 2 | final TResult data; 3 | final TStatus status; 4 | 5 | Result(this.data, this.status); 6 | 7 | factory Result.submit(TResult data, TStatus status) { 8 | return Result(data, status); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ecommers/lib/extensions/index.dart: -------------------------------------------------------------------------------- 1 | export 'json_extension.dart'; 2 | export 'string_extension.dart'; 3 | -------------------------------------------------------------------------------- /ecommers/lib/extensions/json_extension.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | extension JsonExtension on JsonCodec { 4 | List decodeList(String json, T Function(Map) fromMap) { 5 | final jsonMap = 6 | (jsonDecode(json) as List).cast>(); 7 | 8 | return jsonMap.map((e) => fromMap(e)).toList(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ecommers/lib/extensions/string_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | extension StringExtension on String { 4 | bool get isNullOrEmpty => this == null || isEmpty; 5 | bool get isNotNullOrEmpty => this != null && isNotEmpty; 6 | 7 | Color fromHexToColor() { 8 | if (this == null) return null; 9 | 10 | final buffer = StringBuffer(); 11 | if (length == 6 || length == 7) buffer.write('ff'); 12 | buffer.write(replaceFirst('#', '')); 13 | return Color(int.parse(buffer.toString(), radix: 16)); 14 | } 15 | 16 | Size size(TextStyle style) { 17 | final TextPainter textPainter = TextPainter( 18 | text: TextSpan(text: this, style: style), 19 | maxLines: 1, 20 | textDirection: TextDirection.ltr) 21 | ..layout(minWidth: 0, maxWidth: double.infinity); 22 | return textPainter.size; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ecommers/lib/shared/app_logger.dart: -------------------------------------------------------------------------------- 1 | import 'package:logger/logger.dart'; 2 | 3 | class AppLogger { 4 | AppLogger() 5 | : _logger = Logger( 6 | level: Level.debug, 7 | printer: PrettyPrinter( 8 | printEmojis: false, methodCount: 0, printTime: false)); 9 | 10 | final Logger _logger; 11 | 12 | void log(Level level, String Function() message) { 13 | _logger.log(level, message()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ecommers/lib/shared/get_it_extension.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:chopper/chopper.dart'; 4 | import 'package:ecommers/core/common/index.dart'; 5 | import 'package:ecommers/core/models/data_models/index.dart'; 6 | import 'package:ecommers/core/models/index.dart'; 7 | import 'package:ecommers/core/services/index.dart'; 8 | import 'package:ecommers/shared/dependency_service.dart'; 9 | import 'package:ecommers/web_server/local_server.dart'; 10 | import 'package:get_it/get_it.dart'; 11 | 12 | extension GetItExtension on GetIt { 13 | void registerHttpClient() { 14 | final chopper = ChopperClient( 15 | baseUrl: LocalServer.uri.origin, 16 | services: [ 17 | ApiService.create(), 18 | ], 19 | interceptors: [ 20 | (Request request) async { 21 | if (membershipService.isNotExpired == true) { 22 | final headers = Map.from(request.headers); 23 | 24 | headers.addAll({ 25 | HttpHeaders.authorizationHeader: 26 | 'Bearer ${membershipService.accessToken}', 27 | }); 28 | 29 | return request.copyWith( 30 | headers: headers, 31 | ); 32 | } 33 | 34 | return request; 35 | } 36 | ], 37 | converter: const JsonSerializableConverter( 38 | factories: { 39 | LoginModel: LoginModel.fromJsonFactory, 40 | Product: Product.fromJsonFactory, 41 | Category: Category.fromJsonFactory, 42 | Note: Note.fromJsonFactory, 43 | }, 44 | ), 45 | ); 46 | 47 | registerLazySingleton(() => ApiService.create(chopper)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ecommers/lib/shared/logger.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/shared/app_logger.dart'; 2 | import 'package:firebase_crashlytics/firebase_crashlytics.dart'; 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:logger/logger.dart'; 5 | 6 | class Logger { 7 | final _appLogger = AppLogger(); 8 | final _remoteLogger = Crashlytics.instance; 9 | 10 | /// Log a message at level [Level.verbose]. 11 | void v(String Function() message) { 12 | _logInternally(Level.verbose, message); 13 | } 14 | 15 | /// Log a message at level [Level.debug]. 16 | void d(String Function() message) { 17 | _logInternally(Level.debug, message); 18 | } 19 | 20 | /// Log a message at level [Level.info]. 21 | void i(String Function() message) { 22 | _logInternally(Level.info, message); 23 | } 24 | 25 | /// Log a message at level [Level.warning]. 26 | void w(String Function() message) { 27 | _logInternally(Level.warning, message); 28 | } 29 | 30 | /// Log a message at level [Level.error]. 31 | void e(String Function() message) { 32 | _logInternally(Level.error, message); 33 | } 34 | 35 | /// Log a message at level [Level.error]. 36 | void ex(dynamic ex, {StackTrace stackTrace}) { 37 | _logException(ex, stackTrace); 38 | } 39 | 40 | /// Log a message at level [Level.wtf]. 41 | void wtf(String Function() message) { 42 | _logInternally(Level.wtf, message); 43 | } 44 | 45 | void _logInternally(Level level, String Function() message) { 46 | _appLogger.log(level, message); 47 | } 48 | 49 | void _logException(dynamic ex, StackTrace stack) { 50 | if (kReleaseMode) { 51 | _remoteLogger.recordError(ex, StackTrace.current); 52 | } else { 53 | e(() => ex.toString()); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ecommers/lib/ui/decorations/backgrounds_for_notifications.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | class BackgroundForNotifications { 4 | static Color orderBackgroundColor = const Color(0xff8B9DFF); 5 | static Color locationPinBackgroundColor = const Color(0xff4AD1C7); 6 | static Color discountBackgroundColor = const Color(0xffFFAF52); 7 | static Color tagBackgroundColor = const Color(0xffADD172); 8 | } 9 | -------------------------------------------------------------------------------- /ecommers/lib/ui/decorations/branding_colors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BrandingColors { 4 | static const Color background = Color(0xffffffff); 5 | static const Color pageBackground = Color(0xffF5F6F8); 6 | static const Color blur = Color(0xffE7EAF0); 7 | static const Color backgroundIcon = Color(0xffDBDEE2); 8 | static const Color primaryText = Color(0xff515C6F); 9 | static const Color secondaryText = Color(0xffffffff); 10 | static const Color primary = Color(0xFFFF6969); 11 | static const Color secondary = Color(0xFF727C8E); 12 | } -------------------------------------------------------------------------------- /ecommers/lib/ui/decorations/dimens/dimens.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'insets.dart'; 4 | 5 | class Dimens { 6 | static const int defaultTextMaxLines = 1; 7 | 8 | static const Offset defaultBlurOffset = Offset(Insets.x0, Insets.x2); 9 | 10 | static const double pagePadding = Insets.x6; 11 | } 12 | -------------------------------------------------------------------------------- /ecommers/lib/ui/decorations/dimens/font_sizes.dart: -------------------------------------------------------------------------------- 1 | class FontSizes { 2 | static const small_1x = 10.0; 3 | static const small_2x = 11.0; 4 | static const small_3x = 12.0; 5 | static const normal = 15.0; 6 | static const big_1x = 18.0; 7 | static const big_2x = 20.0; 8 | static const big_3x = 22.0; 9 | static const big_4x = 30.0; 10 | } -------------------------------------------------------------------------------- /ecommers/lib/ui/decorations/dimens/index.dart: -------------------------------------------------------------------------------- 1 | export 'dimens.dart'; 2 | export 'font_sizes.dart'; 3 | export 'insets.dart'; 4 | export 'radiuses.dart'; 5 | -------------------------------------------------------------------------------- /ecommers/lib/ui/decorations/dimens/insets.dart: -------------------------------------------------------------------------------- 1 | class Insets { 2 | static const x0 = 0.0; 3 | static const x0_5 = 2.0; 4 | static const x1 = 4.0; 5 | static const x1_5 = 6.0; 6 | static const x2 = 8.0; 7 | static const x2_5 = 10.0; 8 | static const x3 = 12.0; 9 | static const x3_5 = 14.0; 10 | static const x4 = 16.0; 11 | static const x4_5 = 18.0; 12 | static const x5 = 20.0; 13 | static const x5_5 = 22.0; 14 | static const x6 = 24.0; 15 | static const x6_5 = 26.0; 16 | static const x7 = 28.0; 17 | static const x7_5 = 30.0; 18 | static const x8 = 32.0; 19 | static const x8_5 = 34.0; 20 | static const x12_5 = 50.0; 21 | static const x25 = 100.0; 22 | } -------------------------------------------------------------------------------- /ecommers/lib/ui/decorations/dimens/radiuses.dart: -------------------------------------------------------------------------------- 1 | class Radiuses { 2 | static const small_1x = 5.0; 3 | static const small_2x = 7.0; 4 | static const normal = 10.0; 5 | static const big_1x = 15.0; 6 | static const big_1_5x = 18.0; 7 | static const big_2x = 24.0; 8 | } -------------------------------------------------------------------------------- /ecommers/lib/ui/decorations/index.dart: -------------------------------------------------------------------------------- 1 | export 'assets.dart'; 2 | export 'branding_colors.dart'; 3 | export 'theme_provider.dart'; 4 | -------------------------------------------------------------------------------- /ecommers/lib/ui/pages/authorization/authentication_tab_base.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AuthorizationTabBase extends StatelessWidget { 5 | final List children; 6 | 7 | const AuthorizationTabBase({this.children}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return LayoutBuilder(builder: (context, viewportConstraints) { 12 | return SingleChildScrollView( 13 | padding: const EdgeInsets.symmetric(horizontal: Dimens.pagePadding), 14 | child: ConstrainedBox( 15 | constraints: BoxConstraints(minHeight: viewportConstraints.maxHeight), 16 | child: IntrinsicHeight( 17 | child: Column( 18 | mainAxisAlignment: MainAxisAlignment.center, 19 | children: children, 20 | ), 21 | ), 22 | ), 23 | ); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ecommers/lib/ui/pages/authorization/index.dart: -------------------------------------------------------------------------------- 1 | export 'authentication_tab_base.dart'; 2 | export 'authorization_page.dart'; 3 | export 'forgot_password_page.dart'; 4 | export 'log_in_page.dart'; 5 | export 'sign_up_page.dart'; 6 | -------------------------------------------------------------------------------- /ecommers/lib/ui/pages/base_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/mixins/busy_notifier.dart'; 2 | import 'package:ecommers/ui/pages/index.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | class BasePage extends StatelessWidget { 7 | final Widget child; 8 | 9 | final T Function() createProvider; 10 | 11 | const BasePage({ 12 | @required this.createProvider, 13 | this.child, 14 | Key key, 15 | }) : super(key: key); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return ChangeNotifierProvider( 20 | create: (_) => createProvider(), 21 | child: BusyPage( 22 | child: child, 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ecommers/lib/ui/pages/busy_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/mixins/busy_notifier.dart'; 2 | import 'package:ecommers/ui/widgets/progress.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | class BusyPage extends StatelessWidget { 7 | final Widget child; 8 | 9 | const BusyPage({Key key, this.child}) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Consumer( 14 | builder: (_, provider, child) { 15 | return Stack( 16 | children: [ 17 | child, 18 | Visibility( 19 | visible: provider.isBusy, 20 | child: Container( 21 | color: Colors.white.withOpacity(0.6), 22 | child: const Progress()), 23 | ) 24 | ], 25 | ); 26 | }, 27 | child: child, 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ecommers/lib/ui/pages/closeable_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/shared/dependency_service.dart'; 2 | import 'package:ecommers/ui/decorations/index.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_svg/svg.dart'; 5 | 6 | class CloseablePage extends StatelessWidget { 7 | final Widget child; 8 | 9 | const CloseablePage({this.child}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | backgroundColor: BrandingColors.pageBackground, 15 | appBar: AppBar( 16 | automaticallyImplyLeading: false, 17 | actions: [ 18 | IconButton( 19 | icon: SvgPicture.asset( 20 | Assets.closeIcon, 21 | color: BrandingColors.primary, 22 | height: 18.0, 23 | ), 24 | onPressed: () => navigationService.goBack(), 25 | ) 26 | ], 27 | ), 28 | body: child, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ecommers/lib/ui/pages/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | 4 | import '../../core/provider_models/index.dart'; 5 | import '../../ui/decorations/dimens/index.dart'; 6 | import '../../ui/pages/index.dart'; 7 | import '../../ui/widgets/category/categories_compact_view.dart'; 8 | import '../../ui/widgets/index.dart'; 9 | 10 | class HomePage extends StatelessWidget { 11 | final ScrollController _controller = 12 | ScrollController(initialScrollOffset: 0.0, keepScrollOffset: true); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return BasePage( 17 | createProvider: () => HomeProviderModel(), 18 | child: Consumer( 19 | builder: (context, provider, child) { 20 | return CustomScrollView( 21 | controller: _controller, 22 | slivers: [ 23 | SliverToBoxAdapter( 24 | child: Column( 25 | crossAxisAlignment: CrossAxisAlignment.stretch, 26 | children: [ 27 | CategoriesCompactView(provider.categoryList), 28 | const SizedBox(height: Insets.x2), 29 | NotesCarousel(notes: provider.notesLatest), 30 | ], 31 | ), 32 | ), 33 | ProductLatestGrid(controller: _controller), 34 | child, 35 | ], 36 | ); 37 | }, 38 | child: const ItemsLoader(), 39 | ), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ecommers/lib/ui/pages/index.dart: -------------------------------------------------------------------------------- 1 | export 'add_payment_method_page.dart'; 2 | export 'add_shipping_address_page.dart'; 3 | export 'base_page.dart'; 4 | export 'busy_page.dart'; 5 | export 'cart_page.dart'; 6 | export 'categories_page.dart'; 7 | export 'checkout_page.dart'; 8 | export 'closeable_page.dart'; 9 | export 'home_page.dart'; 10 | export 'more_page.dart'; 11 | export 'note_page.dart'; 12 | export 'notifications_page.dart'; 13 | export 'payment_method_page.dart'; 14 | export 'product_page.dart'; 15 | export 'products_grid_page.dart'; 16 | export 'profile_edit_page.dart'; 17 | export 'profile_page.dart'; 18 | export 'search_page.dart'; 19 | export 'shell_page.dart'; 20 | export 'shipping_address_page.dart'; 21 | export 'success_page.dart'; 22 | export 'success_page.dart'; -------------------------------------------------------------------------------- /ecommers/lib/ui/utils/formatter.dart: -------------------------------------------------------------------------------- 1 | import 'package:intl/intl.dart'; 2 | 3 | class Formatter { 4 | static String getCost(double cost) { 5 | final currencyFormatter = NumberFormat.simpleCurrency(); 6 | 7 | return currencyFormatter.format(cost); 8 | } 9 | 10 | static String getTextWithNumberCard(String lastFourNumber) { 11 | if (lastFourNumber == null || lastFourNumber.isEmpty) return null; 12 | 13 | return '************$lastFourNumber'; 14 | } 15 | 16 | static String getTextWithSpecifiedDateFormat(DateTime date, String format) { 17 | return DateFormat(format).format(date); 18 | } 19 | 20 | static String getRate(double value) { 21 | return value.toStringAsFixed(1); 22 | } 23 | 24 | static String getAlias(String firstName, String lastName) { 25 | return firstName?.isNotEmpty == true && lastName?.isNotEmpty == true 26 | ? '${firstName[0]}${lastName[0]}' 27 | : ''; 28 | } 29 | 30 | static String getUserName(String firstName, String lastName) { 31 | return firstName?.isNotEmpty == true && lastName?.isNotEmpty == true 32 | ? '$firstName $lastName' 33 | : 'No Name'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ecommers/lib/ui/utils/index.dart: -------------------------------------------------------------------------------- 1 | export 'formatter.dart'; 2 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/authorization/auth_form.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../index.dart'; 4 | 5 | class AuthForm extends StatefulWidget { 6 | final GlobalKey formKey = GlobalKey(); 7 | 8 | final Widget child; 9 | 10 | AuthForm({this.child}); 11 | 12 | @override 13 | _AuthFormState createState() => _AuthFormState(); 14 | } 15 | 16 | class _AuthFormState extends State { 17 | @override 18 | Widget build(BuildContext context) { 19 | return Form( 20 | key: widget.formKey, 21 | child: SurfaceContainer( 22 | child: widget.child, 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/authorization/index.dart: -------------------------------------------------------------------------------- 1 | export 'auth_form.dart'; 2 | export 'auth_rich_text.dart'; 3 | export 'auth_text_field.dart'; 4 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/back_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/shared/dependency_service.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_svg/svg.dart'; 4 | 5 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 6 | import 'package:ecommers/ui/decorations/index.dart'; 7 | 8 | class BackButton extends StatelessWidget { 9 | const BackButton({Key key}) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return IconButton( 14 | icon: SvgPicture.asset( 15 | Assets.backIcon, 16 | color: BrandingColors.primary, 17 | height: Insets.x4_5, 18 | ), 19 | onPressed: () => navigationService.goBack(), 20 | ); 21 | } 22 | } -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/backgrounded_safe_area.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/ui/decorations/index.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class BackgroundedSafeArea extends StatelessWidget { 5 | final Widget child; 6 | final bool isBottom; 7 | 8 | const BackgroundedSafeArea({ 9 | Key key, 10 | this.child, 11 | this.isBottom = true, 12 | }) : super(key: key); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Container( 17 | color: BrandingColors.pageBackground, 18 | child: SafeArea(bottom: isBottom, child: child), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/bottom_navigation/bottom_navigation_item_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BottomNavigationItemModel { 4 | final IconData icon; 5 | final String title; 6 | 7 | BottomNavigationItemModel({ 8 | @required this.icon, 9 | @required this.title, 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/bottom_navigation/buttom_bar_item_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:badges/badges.dart'; 2 | import 'package:ecommers/core/provider_models/index.dart'; 3 | import 'package:ecommers/shared/dependency_service.dart'; 4 | import 'package:ecommers/ui/decorations/dimens/insets.dart'; 5 | import 'package:ecommers/ui/widgets/index.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:provider/provider.dart'; 8 | 9 | class ButtomBarItemIcon extends StatelessWidget { 10 | final IconData iconData; 11 | final bool hasBadge; 12 | 13 | static const _iconWithBadgeWidth = 41.0; 14 | 15 | const ButtomBarItemIcon({ 16 | @required this.iconData, 17 | this.hasBadge = false, 18 | }); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | 23 | if (hasBadge) { 24 | return Selector( 25 | builder: (context, data, child) { 26 | return Container( 27 | alignment: Alignment.center, 28 | width: _iconWithBadgeWidth, 29 | child: IconWithBadge( 30 | badgePosition: 31 | BadgePosition.bottomLeft(bottom: Insets.x1, left: -Insets.x4), 32 | badgeTextStyle: textTheme.overline, 33 | icon: Icon(iconData), 34 | badgeValue: data, 35 | ), 36 | ); 37 | }, 38 | selector: (buildContext, cartProvider) => cartProvider.orderCount, 39 | ); 40 | } 41 | return Icon(iconData); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/bottom_navigation/consts.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/common/index.dart'; 2 | import 'package:ecommers/ui/widgets/bottom_navigation/bottom_navigation_item_model.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | final Map bottomNavigationItems = { 6 | Pages.home: BottomNavigationItemModel(icon: Icons.home, title: 'Home'), 7 | Pages.search: BottomNavigationItemModel(icon: Icons.search, title: 'Search'), 8 | Pages.cart: BottomNavigationItemModel(icon: Icons.shopping_cart, title: 'Cart'), 9 | Pages.profile: BottomNavigationItemModel(icon: Icons.person_outline, title: 'Profile'), 10 | Pages.more: BottomNavigationItemModel(icon: Icons.menu, title: 'More'), 11 | }; 12 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/button/index.dart: -------------------------------------------------------------------------------- 1 | export 'button_base_widget.dart'; 2 | export 'primary_button_widget.dart'; 3 | export 'secondary_button_widget.dart'; 4 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/button/primary_button_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'package:ecommers/ui/decorations/index.dart'; 4 | import 'package:ecommers/ui/widgets/button/index.dart'; 5 | 6 | class PrimaryButtonWidget extends ButtonBaseWidget { 7 | PrimaryButtonWidget({ 8 | @required String text, 9 | @required Function() onPressedFunction, 10 | bool isDisabled = false, 11 | String assetIconPath = Assets.arrowRightIcon, 12 | }) : super( 13 | text: text, 14 | assetIcon: assetIconPath, 15 | buttonColor: BrandingColors.primary, 16 | textColor: BrandingColors.secondaryText, 17 | onPressedFunction: onPressedFunction, 18 | blurColor: BrandingColors.primary.withOpacity(0.4), 19 | isDisabled: isDisabled, 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/button/secondary_button_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/ui/decorations/index.dart'; 2 | import 'package:ecommers/ui/widgets/button/index.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class SecondaryButtonWidget extends ButtonBaseWidget { 6 | SecondaryButtonWidget({ 7 | @required String text, 8 | @required String assetIcon, 9 | @required Function() onPressedFunction, 10 | }) : super( 11 | text: text, 12 | assetIcon: assetIcon, 13 | buttonColor: BrandingColors.background, 14 | textColor: BrandingColors.secondary, 15 | onPressedFunction: onPressedFunction, 16 | blurColor: BrandingColors.secondary.withOpacity(0.15), 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/cached_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:ecommers/ui/decorations/index.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_svg/svg.dart'; 5 | 6 | class CachedImage extends StatelessWidget { 7 | final String imagePath; 8 | final BoxFit boxFit; 9 | final String placeholder; 10 | 11 | const CachedImage({ 12 | @required this.imagePath, 13 | this.boxFit = BoxFit.scaleDown, 14 | this.placeholder, 15 | }); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return CachedNetworkImage( 20 | placeholder: placeholder == null 21 | ? null 22 | : (_, __) => CachedNetworkImage(imageUrl: placeholder, fit: boxFit), 23 | imageUrl: imagePath, 24 | placeholderFadeInDuration: const Duration(seconds: 0), 25 | errorWidget: (context, url, error) => 26 | SvgPicture.asset(Assets.warningIcon), 27 | fit: boxFit, 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/circle_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 2 | import 'package:ecommers/ui/decorations/index.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_svg/svg.dart'; 5 | 6 | class CircleIcon extends StatelessWidget { 7 | static const size = Size(Insets.x4_5, Insets.x4_5); 8 | 9 | final String imagePath; 10 | final Color backgroundColor; 11 | final Color iconColor; 12 | 13 | const CircleIcon({ 14 | this.imagePath = Assets.arrowIcon, 15 | this.backgroundColor = BrandingColors.backgroundIcon, 16 | this.iconColor = BrandingColors.secondary, 17 | }); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Container( 22 | width: size.width, 23 | height: size.height, 24 | alignment: Alignment.center, 25 | decoration: BoxDecoration( 26 | shape: BoxShape.circle, 27 | color: backgroundColor, 28 | ), 29 | child: Padding( 30 | padding: const EdgeInsets.all(Insets.x1), 31 | child: SvgPicture.asset( 32 | imagePath, 33 | fit: BoxFit.scaleDown, 34 | color: iconColor, 35 | ), 36 | ), 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/hero_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'index.dart'; 4 | 5 | class HeroImage extends StatelessWidget { 6 | final String imagePath; 7 | final String placeholder; 8 | final BoxFit boxFit; 9 | final dynamic tag; 10 | 11 | const HeroImage({ 12 | @required this.imagePath, 13 | this.tag, 14 | this.boxFit = BoxFit.scaleDown, 15 | this.placeholder, 16 | }); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Hero( 21 | tag: tag ?? imagePath, 22 | child: CachedImage( 23 | placeholder: placeholder, 24 | imagePath: imagePath, 25 | boxFit: boxFit, 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/icon_with_badge.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:badges/badges.dart'; 3 | import '../decorations/dimens/index.dart'; 4 | import '../decorations/index.dart'; 5 | 6 | class IconWithBadge extends Badge { 7 | final int badgeValue; 8 | final BadgePosition badgePosition; 9 | final Widget icon; 10 | final TextStyle badgeTextStyle; 11 | 12 | IconWithBadge({ 13 | this.badgeValue = 0, 14 | this.badgePosition, 15 | this.badgeTextStyle, 16 | @required this.icon, 17 | }) : super( 18 | child: icon, 19 | badgeContent: Text( 20 | badgeValue.toString(), 21 | style: badgeTextStyle, 22 | textAlign: TextAlign.center, 23 | ), 24 | position: 25 | badgePosition ?? BadgePosition.bottomLeft(bottom: -4, left: -9), 26 | shape: BadgeShape.square, 27 | borderRadius: Radiuses.small_2x, 28 | elevation: 1.0, 29 | badgeColor: BrandingColors.primary, 30 | animationType: BadgeAnimationType.scale, 31 | showBadge: badgeValue != 0, 32 | padding: const EdgeInsets.fromLTRB( 33 | Insets.x1_5, 34 | Insets.x0_5, 35 | Insets.x1_5, 36 | Insets.x0_5, 37 | ), 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/index.dart: -------------------------------------------------------------------------------- 1 | export 'address_card.dart'; 2 | export 'back_button.dart'; 3 | export 'backgrounded_safe_area.dart'; 4 | export 'bank_card.dart'; 5 | export 'cached_image.dart'; 6 | export 'carousel_widget.dart'; 7 | export 'circle_icon.dart'; 8 | export 'credit_card_text_field.dart'; 9 | export 'hero_image.dart'; 10 | export 'icon_with_badge.dart'; 11 | export 'image_card.dart'; 12 | export 'items_loader.dart'; 13 | export 'notes_carousel.dart'; 14 | export 'product_latest_grid.dart'; 15 | export 'products_grid.dart'; 16 | export 'progress.dart'; 17 | export 'rate_widget.dart'; 18 | export 'slide_menu.dart'; 19 | export 'surface_container.dart'; -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/items_loader.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | 4 | import 'package:ecommers/core/mixins/items_loading_notifier.dart'; 5 | import 'package:ecommers/ui/decorations/index.dart'; 6 | 7 | const double scrollOffsetDelta = 100.0; 8 | 9 | class ItemsLoader extends StatelessWidget { 10 | static const loaderHeight = 60.0; 11 | 12 | const ItemsLoader({Key key}) : super(key: key); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Selector( 17 | builder: (_, isLoading, child) { 18 | return isLoading 19 | ? SliverToBoxAdapter( 20 | child: Container( 21 | height: loaderHeight, 22 | alignment: Alignment.center, 23 | child: const CircularProgressIndicator( 24 | valueColor: 25 | AlwaysStoppedAnimation(BrandingColors.primary), 26 | ), 27 | ), 28 | ) 29 | : const SliverToBoxAdapter( 30 | child: SizedBox(height: loaderHeight), 31 | ); 32 | }, 33 | selector: (_, provider) => provider.isItemsLoading, 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/menu/index.dart: -------------------------------------------------------------------------------- 1 | export 'menu_item.dart'; 2 | export 'menu_item_model.dart'; 3 | export 'menu_list.dart'; 4 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/menu/menu_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/shared/dependency_service.dart'; 2 | import 'package:ecommers/ui/widgets/index.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_svg/svg.dart'; 5 | 6 | class MenuItem extends StatelessWidget { 7 | final String svgAssetIconPath; 8 | final String title; 9 | final String subTitle; 10 | final double height; 11 | final Function() onTap; 12 | 13 | const MenuItem({ 14 | this.svgAssetIconPath, 15 | this.title, 16 | this.subTitle, 17 | this.height, 18 | this.onTap, 19 | }); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return InkWell( 24 | onTap: onTap, 25 | child: SizedBox( 26 | height: height, 27 | child: Row( 28 | mainAxisAlignment: MainAxisAlignment.center, 29 | children: [ 30 | if (svgAssetIconPath != null) 31 | SizedBox( 32 | width: 57.0, 33 | child: SvgPicture.asset(svgAssetIconPath), 34 | ) 35 | else 36 | const SizedBox(width: 15.0), 37 | Expanded( 38 | child: Text( 39 | title ?? '', 40 | style: textTheme.subtitle1, 41 | ), 42 | ), 43 | Text( 44 | subTitle ?? '', 45 | style: textTheme.subtitle2, 46 | ), 47 | const SizedBox(width: 10.0), 48 | const CircleIcon(), 49 | const SizedBox(width: 15.0), 50 | ], 51 | ), 52 | ), 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/menu/menu_item_model.dart: -------------------------------------------------------------------------------- 1 | class MenuItemModel { 2 | final String svgAssetIconPath; 3 | final String title; 4 | final String subTitle; 5 | final Function() onTappedFunction; 6 | 7 | const MenuItemModel({ 8 | this.svgAssetIconPath, 9 | this.title, 10 | this.subTitle, 11 | this.onTappedFunction, 12 | }); 13 | } -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/menu/menu_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'package:ecommers/ui/decorations/index.dart'; 4 | import 'package:ecommers/ui/widgets/index.dart'; 5 | import 'package:ecommers/ui/widgets/menu/index.dart'; 6 | 7 | class MenuList extends StatelessWidget { 8 | static const itemHeight = 48.0; 9 | 10 | final List itemList; 11 | final EdgeInsets margin; 12 | 13 | const MenuList({ 14 | this.itemList, 15 | this.margin, 16 | }); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Column( 21 | crossAxisAlignment: CrossAxisAlignment.start, 22 | children: [ 23 | SurfaceContainer( 24 | margin: margin, 25 | child: ListView.separated( 26 | shrinkWrap: true, 27 | physics: const NeverScrollableScrollPhysics(), 28 | itemCount: itemList.length, 29 | padding: const EdgeInsets.all(0.0), 30 | itemBuilder: (context, index) { 31 | final itemModel = itemList[index]; 32 | 33 | return MenuItem( 34 | title: itemModel.title, 35 | subTitle: itemModel.subTitle, 36 | svgAssetIconPath: itemModel.svgAssetIconPath, 37 | height: itemHeight, 38 | onTap: itemModel.onTappedFunction, 39 | ); 40 | }, 41 | separatorBuilder: (context, index) { 42 | return Divider( 43 | color: BrandingColors.secondary.withOpacity(0.1), 44 | height: 1.0, 45 | indent: 57.0, 46 | endIndent: 17.0, 47 | thickness: 1, 48 | ); 49 | }, 50 | ), 51 | ), 52 | ], 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/order/circle_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 2 | import 'package:ecommers/ui/decorations/index.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class CircleImage extends StatelessWidget { 6 | final Widget image; 7 | final Size size; 8 | 9 | const CircleImage({ 10 | @required this.image, 11 | @required this.size, 12 | }); 13 | @override 14 | Widget build(BuildContext context) { 15 | return Container( 16 | alignment: Alignment.center, 17 | height: size.height, 18 | width: size.width, 19 | padding: const EdgeInsets.all(Insets.x2), 20 | decoration: const BoxDecoration( 21 | shape: BoxShape.circle, 22 | color: BrandingColors.background, 23 | ), 24 | child: image, 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/order/index.dart: -------------------------------------------------------------------------------- 1 | export 'circle_image.dart'; 2 | export 'counter.dart'; 3 | export 'order_widget.dart'; 4 | export 'small_order_widget.dart'; 5 | export 'total_order_widget.dart'; 6 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/product_item/index.dart: -------------------------------------------------------------------------------- 1 | export 'product_item_base.dart'; 2 | export 'product_item_normal.dart'; 3 | export 'product_item_small.dart'; 4 | export 'product_item_wide.dart'; 5 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/product_item/product_item_base.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/data_models/index.dart'; 2 | import 'package:ecommers/shared/dependency_service.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | import 'package:ecommers/core/common/index.dart'; 6 | import 'package:ecommers/ui/widgets/index.dart'; 7 | 8 | abstract class ProductItemBase extends StatelessWidget { 9 | @protected 10 | static const double padding = 10.0; 11 | 12 | final Product product; 13 | final Size productSize; 14 | 15 | const ProductItemBase({ 16 | @required this.product, 17 | @required this.productSize, 18 | }); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return SurfaceContainer( 23 | padding: const EdgeInsets.all(10.0), 24 | height: productSize.height, 25 | width: productSize.width, 26 | child: GestureDetector( 27 | onTap: () => { 28 | navigationService.navigateTo(Pages.product, arguments: product), 29 | }, 30 | child: buildProductItem(context), 31 | ), 32 | ); 33 | } 34 | 35 | Widget buildProductItem(BuildContext context); 36 | } 37 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/product_item/product_item_normal.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/data_models/index.dart'; 2 | import 'package:ecommers/shared/dependency_service.dart'; 3 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 4 | import 'package:ecommers/ui/utils/formatter.dart'; 5 | import 'package:ecommers/ui/widgets/index.dart'; 6 | import 'package:ecommers/ui/widgets/product_item/product_item_base.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter/widgets.dart'; 9 | 10 | class ProductItemNormal extends ProductItemBase { 11 | static const size = Size(101.0, 135.0); 12 | 13 | const ProductItemNormal({ 14 | @required Product product, 15 | }) : super( 16 | product: product, 17 | productSize: size, 18 | ); 19 | 20 | @override 21 | Widget buildProductItem(BuildContext context) { 22 | return Column( 23 | crossAxisAlignment: CrossAxisAlignment.start, 24 | children: [ 25 | Expanded( 26 | child: Center( 27 | child: HeroImage( 28 | tag: product.id, 29 | imagePath: product.previewImage, 30 | ), 31 | ), 32 | ), 33 | const SizedBox(height: 4.0), 34 | Text( 35 | product.title, 36 | overflow: TextOverflow.ellipsis, 37 | maxLines: Dimens.defaultTextMaxLines, 38 | style: textTheme.bodyText2.copyWith(fontSize: FontSizes.small_3x), 39 | ), 40 | Text( 41 | Formatter.getCost(product.price), 42 | style: textTheme.bodyText2.copyWith( 43 | fontSize: FontSizes.small_1x, 44 | fontWeight: FontWeight.w700, 45 | ), 46 | ), 47 | ], 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/product_item/product_item_small.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/shared/dependency_service.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import 'package:ecommers/core/models/data_models/index.dart'; 5 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 6 | import 'package:ecommers/ui/utils/formatter.dart'; 7 | import 'package:ecommers/ui/widgets/index.dart'; 8 | import 'package:ecommers/ui/widgets/product_item/product_item_base.dart'; 9 | 10 | class ProductItemSmall extends ProductItemBase { 11 | static const size = Size(185.0, 59.0); 12 | 13 | const ProductItemSmall({ 14 | @required Product product, 15 | }) : super( 16 | product: product, 17 | productSize: size, 18 | ); 19 | 20 | @override 21 | Widget buildProductItem(BuildContext context) { 22 | return Row( 23 | mainAxisAlignment: MainAxisAlignment.start, 24 | children: [ 25 | Expanded( 26 | flex: 3, 27 | child: CachedImage(imagePath: product.previewImage), 28 | ), 29 | const SizedBox( 30 | width: ProductItemBase.padding, 31 | ), 32 | Expanded( 33 | flex: 7, 34 | child: Column( 35 | mainAxisAlignment: MainAxisAlignment.end, 36 | crossAxisAlignment: CrossAxisAlignment.start, 37 | children: [ 38 | Text( 39 | product.title, 40 | overflow: TextOverflow.ellipsis, 41 | maxLines: Dimens.defaultTextMaxLines, 42 | style: textTheme 43 | .bodyText1 44 | .copyWith(fontWeight: FontWeight.w400), 45 | ), 46 | Text( 47 | Formatter.getCost(product.price), 48 | style: textTheme.bodyText1, 49 | ), 50 | ], 51 | ), 52 | ) 53 | ], 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/product_item/product_item_wide.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/data_models/index.dart'; 2 | import 'package:ecommers/shared/dependency_service.dart'; 3 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 4 | import 'package:ecommers/ui/utils/formatter.dart'; 5 | import 'package:ecommers/ui/widgets/index.dart'; 6 | import 'package:ecommers/ui/widgets/product_item/product_item_base.dart'; 7 | import 'package:flutter/material.dart'; 8 | 9 | class ProductItemWide extends ProductItemBase { 10 | static const size = Size(160.0, 218.0); 11 | 12 | const ProductItemWide({@required Product product}) 13 | : super( 14 | product: product, 15 | productSize: size, 16 | ); 17 | 18 | @override 19 | Widget buildProductItem(BuildContext context) { 20 | return Column( 21 | crossAxisAlignment: CrossAxisAlignment.start, 22 | children: [ 23 | Expanded( 24 | child: Center( 25 | child: HeroImage( 26 | tag: product.id, 27 | imagePath: product.previewImage, 28 | ), 29 | ), 30 | ), 31 | Text( 32 | product.title, 33 | maxLines: Dimens.defaultTextMaxLines, 34 | overflow: TextOverflow.ellipsis, 35 | style: textTheme.bodyText2, 36 | ), 37 | Row( 38 | children: [ 39 | Expanded( 40 | child: Text( 41 | Formatter.getCost(product.price), 42 | style: textTheme.bodyText2.copyWith( 43 | fontSize: FontSizes.small_3x, 44 | fontWeight: FontWeight.w700, 45 | ), 46 | ), 47 | ), 48 | RateWidget( 49 | rate: product.rate, 50 | ), 51 | ], 52 | ) 53 | ], 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/product_page/index.dart: -------------------------------------------------------------------------------- 1 | export 'details_tab.dart'; 2 | export 'header.dart'; 3 | export 'product_page_bottom_view.dart'; 4 | export 'product_tab.dart'; 5 | export 'reviews_tab.dart'; 6 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/product_page/product_page_bottom_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/shared/dependency_service.dart'; 2 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 3 | import 'package:ecommers/ui/decorations/index.dart'; 4 | import 'package:ecommers/ui/widgets/button/index.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | class ProductPageBottomView extends StatelessWidget { 8 | final Function() addToCartFunction; 9 | 10 | const ProductPageBottomView({@required this.addToCartFunction}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Column( 15 | children: [ 16 | Row( 17 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 18 | children: [ 19 | Flexible( 20 | child: SecondaryButtonWidget( 21 | text: localization.shareThis, 22 | onPressedFunction: () => {}, 23 | assetIcon: Assets.shareArrowIcon, 24 | ), 25 | ), 26 | const SizedBox(width: Insets.x7), 27 | Flexible( 28 | child: PrimaryButtonWidget( 29 | text: localization.addToCart, 30 | onPressedFunction: addToCartFunction, 31 | ), 32 | ), 33 | ], 34 | ), 35 | ], 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/profile/profile_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:ecommers/ui/decorations/assets.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class ProfileImage extends StatelessWidget { 6 | final double profileCardHeight; 7 | 8 | const ProfileImage(this.profileCardHeight); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Container( 13 | height: profileCardHeight, 14 | width: profileCardHeight, 15 | decoration: const BoxDecoration( 16 | shape: BoxShape.circle, 17 | image: DecorationImage( 18 | image: CachedNetworkImageProvider( 19 | '${Assets.imageBaseUrl}/${Assets.girlImage}'), 20 | fit: BoxFit.cover, 21 | ), 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/progress.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | import '../../ui/decorations/dimens/index.dart'; 7 | import '../../ui/decorations/index.dart'; 8 | 9 | class Progress extends StatelessWidget { 10 | static const double _progressSide = 40.0; 11 | static const double _containerSide = _progressSide + 30.0; 12 | 13 | const Progress({Key key}) : super(key: key); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Center( 18 | child: Container( 19 | height: _containerSide, 20 | width: _containerSide, 21 | alignment: Alignment.center, 22 | decoration: BoxDecoration( 23 | color: Colors.black.withOpacity(0.2), 24 | borderRadius: BorderRadius.circular(Radiuses.normal), 25 | ), 26 | child: const SizedBox( 27 | height: _progressSide, 28 | width: _progressSide, 29 | child: CircularProgressIndicator( 30 | valueColor: AlwaysStoppedAnimation(BrandingColors.primary), 31 | ), 32 | ), 33 | ), 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/rate_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/shared/dependency_service.dart'; 2 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 3 | import 'package:ecommers/ui/decorations/index.dart'; 4 | import 'package:ecommers/ui/utils/formatter.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_svg/svg.dart'; 7 | 8 | class RateWidget extends StatelessWidget { 9 | final Size size; 10 | final double rate; 11 | 12 | static const rateContainerSize = Size(33.0, 16.0); 13 | 14 | const RateWidget({ 15 | @required this.rate, 16 | this.size, 17 | }); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | final containerSize = size ?? rateContainerSize; 22 | 23 | return Container( 24 | height: containerSize.height, 25 | width: containerSize.width, 26 | alignment: Alignment.center, 27 | decoration: BoxDecoration( 28 | color: BrandingColors.primary, 29 | borderRadius: BorderRadius.circular(Radiuses.big_1x), 30 | ), 31 | child: Center( 32 | child: Row( 33 | mainAxisAlignment: MainAxisAlignment.center, 34 | children: [ 35 | SvgPicture.asset(Assets.starIcon), 36 | Text( 37 | Formatter.getRate(rate), 38 | style: textTheme.overline, 39 | ) 40 | ], 41 | ), 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/right_menu_bar/index.dart: -------------------------------------------------------------------------------- 1 | export 'right_menu_item.dart'; 2 | export 'right_menu_items_list.dart'; 3 | export 'right_menu_widget.dart'; 4 | export 'subtitle_factory.dart'; 5 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/right_menu_bar/models/carousel_image.dart: -------------------------------------------------------------------------------- 1 | class CarouselImage { 2 | final String path; 3 | final String previewImage; 4 | 5 | CarouselImage({this.path, this.previewImage}); 6 | } 7 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/right_menu_bar/models/index.dart: -------------------------------------------------------------------------------- 1 | export 'carousel_image.dart'; 2 | export 'right_menu_colors_model.dart'; 3 | export 'right_menu_item_model.dart'; 4 | export 'right_menu_price_model.dart'; 5 | export 'right_menu_subtitle_model.dart'; 6 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/right_menu_bar/models/right_menu_colors_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/ui/widgets/right_menu_bar/models/index.dart'; 2 | 3 | class RightMenuColorsModel extends RightMenuItemModel { 4 | final List colors; 5 | 6 | RightMenuColorsModel({String title, this.colors}) : super(title: title); 7 | } 8 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/right_menu_bar/models/right_menu_item_model.dart: -------------------------------------------------------------------------------- 1 | class RightMenuItemModel { 2 | final String title; 3 | 4 | RightMenuItemModel({this.title}); 5 | } 6 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/right_menu_bar/models/right_menu_price_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/ui/widgets/right_menu_bar/models/index.dart'; 2 | 3 | class RigthMenuPriceModel extends RightMenuItemModel { 4 | final String minPrice; 5 | final String maxPrice; 6 | 7 | RigthMenuPriceModel({String title, this.minPrice, this.maxPrice}) 8 | : super(title: title); 9 | } 10 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/right_menu_bar/models/right_menu_subtitle_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/ui/widgets/right_menu_bar/models/index.dart'; 2 | 3 | class RightMenuSubTitleModel extends RightMenuItemModel { 4 | final String subTitle; 5 | 6 | RightMenuSubTitleModel({String title, this.subTitle}) : super(title: title); 7 | } 8 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/right_menu_bar/right_menu_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/shared/dependency_service.dart'; 2 | import 'package:ecommers/ui/widgets/right_menu_bar/subtitle_factory.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | import 'package:flutter_svg/svg.dart'; 6 | import 'package:ecommers/ui/decorations/index.dart'; 7 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 8 | 9 | import 'models/right_menu_item_model.dart'; 10 | 11 | @immutable 12 | class RightMenuItem extends StatelessWidget { 13 | final RightMenuItemModel itemModel; 14 | 15 | const RightMenuItem({this.itemModel}); 16 | static const double _height = 50.0; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Container( 21 | height: _height, 22 | child: Row( 23 | children: [ 24 | Expanded( 25 | child: Text( 26 | itemModel.title, 27 | style: textTheme.subtitle1, 28 | ), 29 | ), 30 | RightMenuSubTitle(model: itemModel), 31 | const SizedBox(width: Insets.x2_5), 32 | SvgPicture.asset(Assets.menuArrowIcon), 33 | ], 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/right_menu_bar/right_menu_items_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/ui/widgets/right_menu_bar/index.dart'; 2 | import 'package:ecommers/ui/widgets/right_menu_bar/models/index.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | 5 | 6 | @immutable 7 | class RightMenuItemsList extends StatelessWidget { 8 | final List itemList; 9 | 10 | const RightMenuItemsList({ 11 | this.itemList 12 | }); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return ListView.builder( 17 | shrinkWrap: true, 18 | padding: const EdgeInsets.all(0), 19 | physics: const NeverScrollableScrollPhysics(), 20 | itemCount: itemList.length, 21 | itemBuilder: (context, index) { 22 | final itemModel = itemList[index]; 23 | return RightMenuItem( 24 | itemModel: itemModel, 25 | ); 26 | }, 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/search/container_with_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/shared/dependency_service.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 5 | import 'package:ecommers/ui/decorations/index.dart'; 6 | 7 | class ContainerWithAction extends StatelessWidget { 8 | final String title; 9 | final String actionText; 10 | final void Function() action; 11 | final Widget child; 12 | 13 | const ContainerWithAction({ 14 | Key key, 15 | this.title, 16 | this.actionText, 17 | this.action, 18 | this.child, 19 | }) : super(key: key); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | if (child == null) return const SizedBox(); 24 | 25 | return Column( 26 | children: [ 27 | Row( 28 | children: [ 29 | Text( 30 | title, 31 | style: textTheme.headline5.copyWith( 32 | fontSize: FontSizes.small_3x, 33 | color: Colors.transparent.withOpacity(0.3), 34 | ), 35 | ), 36 | const Spacer(), 37 | InkWell( 38 | onTap: () => action(), 39 | child: Text( 40 | actionText, 41 | style: textTheme.headline5.copyWith( 42 | fontSize: FontSizes.small_3x, 43 | color: BrandingColors.primary), 44 | ), 45 | ), 46 | ], 47 | ), 48 | const SizedBox(height: Insets.x5), 49 | child, 50 | ], 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/search/index.dart: -------------------------------------------------------------------------------- 1 | export 'container_with_action.dart'; 2 | export 'recent_product_list.dart'; 3 | export 'search_button.dart'; 4 | export 'search_recommended_widget.dart'; 5 | export 'search_text_field.dart'; 6 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/search/search_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/shared/dependency_service.dart'; 2 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 3 | import 'package:ecommers/ui/decorations/index.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter/widgets.dart'; 7 | 8 | class SearchButton extends StatelessWidget { 9 | final Function() onPressed; 10 | 11 | const SearchButton({Key key, this.onPressed}) : super(key: key); 12 | @override 13 | Widget build(BuildContext context) { 14 | return SizedBox( 15 | height: 35, 16 | child: CupertinoButton( 17 | padding: const EdgeInsets.all(Insets.x2), 18 | borderRadius: BorderRadius.circular(Radiuses.big_2x), 19 | color: BrandingColors.blur, 20 | onPressed: onPressed, 21 | child: Row( 22 | mainAxisAlignment: MainAxisAlignment.center, 23 | children: [ 24 | const Icon( 25 | Icons.search, 26 | size: FontSizes.normal, 27 | color: BrandingColors.primaryText, 28 | ), 29 | const SizedBox(width: Insets.x2), 30 | Text( 31 | localization.searchHintText, 32 | style: textTheme.bodyText1.copyWith( 33 | fontWeight: FontWeight.w400, 34 | ), 35 | ) 36 | ], 37 | ), 38 | ), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ecommers/lib/ui/widgets/surface_container.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/ui/decorations/dimens/index.dart'; 2 | import 'package:ecommers/ui/decorations/index.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class SurfaceContainer extends StatelessWidget { 6 | final double borderRadius; 7 | final Color backgroundColor; 8 | final EdgeInsets margin; 9 | final EdgeInsets padding; 10 | final double height; 11 | final double width; 12 | final Widget child; 13 | 14 | const SurfaceContainer({ 15 | Key key, 16 | this.borderRadius = Radiuses.normal, 17 | this.backgroundColor = BrandingColors.background, 18 | this.margin = const EdgeInsets.all(0.0), 19 | this.padding = const EdgeInsets.all(0.0), 20 | this.height, 21 | this.width, 22 | @required this.child, 23 | }) : super(key: key); 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Container( 28 | margin: margin, 29 | padding: padding, 30 | alignment: Alignment.center, 31 | height: height, 32 | width: width, 33 | decoration: BoxDecoration( 34 | borderRadius: BorderRadius.circular(borderRadius), 35 | color: backgroundColor, 36 | boxShadow: const [ 37 | BoxShadow( 38 | offset: Dimens.defaultBlurOffset, 39 | blurRadius: Radiuses.big_1x, 40 | color: BrandingColors.blur, 41 | ) 42 | ], 43 | ), 44 | child: child, 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ecommers/lib/web_server/config.dart: -------------------------------------------------------------------------------- 1 | class Config { 2 | static const String jwtSecret = '56C78D53F18D33A30CC4A9628B225BD682A3F85455B663963F3AA1A28385C608'; 3 | static const String refreshToken = 'some refresh token'; 4 | static const String expirationDate = '2021-01-01 12:00:00'; 5 | } -------------------------------------------------------------------------------- /ecommers/lib/web_server/data_access/products_data_access.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/data_models/index.dart'; 2 | import 'package:ecommers/web_server/local_database.dart'; 3 | 4 | class ProductsDataAccess { 5 | static final ProductsDataAccess _instance = ProductsDataAccess._(); 6 | static ProductsDataAccess get instance => _instance; 7 | 8 | final LocalDatabase _database = LocalDatabase.instance; 9 | 10 | ProductsDataAccess._(); 11 | 12 | String _generateRecentKey(String key) { 13 | const String recentProductsStoreKey = 'RecentProducts'; 14 | 15 | return '$recentProductsStoreKey$key'; 16 | } 17 | 18 | Future> getAllRecentProducts(String key) async { 19 | return _database.getAll(_generateRecentKey(key), Product.fromJsonFactory); 20 | } 21 | 22 | Future saveRecentProduct( 23 | Map recentProductMap, 24 | String key, 25 | ) async { 26 | _database.saveMap(_generateRecentKey(key), recentProductMap); 27 | } 28 | 29 | Future deleteRecentProducts( 30 | String key, 31 | ) async { 32 | _database.deleteAll(_generateRecentKey(key)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ecommers/lib/web_server/data_access/validation_model.dart: -------------------------------------------------------------------------------- 1 | class ValidationModel { 2 | final String error; 3 | final bool isValid; 4 | 5 | ValidationModel({this.error = '',this.isValid}); 6 | } -------------------------------------------------------------------------------- /ecommers/lib/web_server/local_database.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:path_provider/path_provider.dart'; 4 | import 'package:sembast/sembast.dart'; 5 | import 'package:sembast/sembast_io.dart'; 6 | import 'package:path/path.dart'; 7 | 8 | class LocalDatabase { 9 | static final LocalDatabase _instance = LocalDatabase._(); 10 | static LocalDatabase get instance => _instance; 11 | 12 | Completer _dbCompleter; 13 | 14 | Future get _db async { 15 | if (_dbCompleter == null) { 16 | _dbCompleter = Completer(); 17 | 18 | await initializeDatabase(); 19 | } 20 | 21 | return _dbCompleter.future; 22 | } 23 | 24 | LocalDatabase._(); 25 | 26 | Future initializeDatabase() async { 27 | final DatabaseFactory dbFactory = databaseFactoryIo; 28 | 29 | final database = await dbFactory.openDatabase(await _getDbPath()); 30 | 31 | _dbCompleter.complete(database); 32 | } 33 | 34 | Future _getDbPath() async { 35 | const _dbName = 'local_server.db'; 36 | 37 | final dbDirectory = await getApplicationDocumentsDirectory(); 38 | if (!dbDirectory.existsSync()) { 39 | await dbDirectory.create(recursive: true); 40 | } 41 | 42 | return join(dbDirectory.path, _dbName); 43 | } 44 | 45 | Future saveMap(String key, Map map) async { 46 | final store = intMapStoreFactory.store(key); 47 | await store.add(await _db, map); 48 | } 49 | 50 | Future> getAll( 51 | String key, T Function(Map) fromMap) async { 52 | final store = intMapStoreFactory.store(key); 53 | final records = await store.find(await _db); 54 | 55 | return records.map((snapshot) { 56 | return fromMap(snapshot.value); 57 | }).toList(); 58 | } 59 | 60 | Future deleteAll(String key) async { 61 | final store = intMapStoreFactory.store(key); 62 | await store.delete(await _db); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ecommers/lib/web_server/local_server.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | import 'dart:math'; 4 | 5 | import 'package:http_server/http_server.dart'; 6 | 7 | import './request_handler.dart'; 8 | import './services/data_provider.dart'; 9 | 10 | class LocalServer { 11 | static const int _port = 8090; 12 | static final String _localHost = InternetAddress.loopbackIPv4.address; 13 | static HttpServer _server; 14 | static Random random = Random(); 15 | 16 | static Uri uri = Uri(scheme: 'http', host: _localHost, port: _port); 17 | 18 | static Future setup() async { 19 | _server = await HttpServer.bind( 20 | _localHost, 21 | _port, 22 | shared: true, 23 | ); 24 | 25 | DataProvider.fetchProducts(); 26 | 27 | _server.transform(HttpBodyHandler()).listen((HttpRequestBody body) async { 28 | final duration = 0.5 + random.nextDouble(); 29 | final seconds = duration.truncate(); 30 | final milliseconds = ((duration - seconds) * 10).round(); 31 | 32 | await Future.delayed(Duration( 33 | seconds: seconds, 34 | milliseconds: milliseconds, 35 | )); 36 | 37 | RequestHandler.process(body); 38 | }); 39 | } 40 | 41 | static void closeConnection() { 42 | if (_server == null) { 43 | return; 44 | } 45 | 46 | _server.close(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ecommers/lib/web_server/query_params/index.dart: -------------------------------------------------------------------------------- 1 | export 'latest_product_query_params.dart'; 2 | export 'product_query_params.dart'; 3 | -------------------------------------------------------------------------------- /ecommers/lib/web_server/query_params/latest_product_query_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/common/index.dart'; 2 | 3 | class LatestProductQueryParams { 4 | final int from; 5 | final int to; 6 | 7 | LatestProductQueryParams({this.from, this.to}); 8 | 9 | factory LatestProductQueryParams.fromQueryParameters( 10 | Map params) { 11 | return LatestProductQueryParams( 12 | from: params[ApiQueryParams.rangeFrom] == null 13 | ? null 14 | : int.tryParse(params[ApiQueryParams.rangeFrom]), 15 | to: params[ApiQueryParams.rangeTo] == null 16 | ? null 17 | : int.tryParse(params[ApiQueryParams.rangeTo])); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ecommers/lib/web_server/query_params/product_query_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:enum_to_string/enum_to_string.dart'; 2 | 3 | import 'package:ecommers/core/common/index.dart'; 4 | import 'package:ecommers/core/models/sort_type.dart'; 5 | 6 | class ProductQueryParams { 7 | final Categories category; 8 | final String subCategory; 9 | final int from; 10 | final int to; 11 | final String searchQuery; 12 | final SortType sortType; 13 | 14 | ProductQueryParams({ 15 | this.category, 16 | this.subCategory, 17 | this.from, 18 | this.to, 19 | this.searchQuery, 20 | this.sortType, 21 | }); 22 | 23 | factory ProductQueryParams.fromQueryParameters(Map params) { 24 | return ProductQueryParams( 25 | category: EnumToString.fromString( 26 | Categories.values, params[ApiQueryParams.category]), 27 | subCategory: params[ApiQueryParams.subCategory], 28 | from: params[ApiQueryParams.rangeFrom] == null 29 | ? null 30 | : int.tryParse(params[ApiQueryParams.rangeFrom]), 31 | to: params[ApiQueryParams.rangeTo] == null 32 | ? null 33 | : int.tryParse(params[ApiQueryParams.rangeTo]), 34 | searchQuery: params[ApiQueryParams.searchQuery], 35 | sortType: EnumToString.fromString( 36 | SortType.values, params[ApiQueryParams.sortType])); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ecommers/lib/web_server/services/authorization_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:ecommers/core/models/data_models/index.dart'; 4 | import 'package:ecommers/core/models/index.dart'; 5 | import 'package:jaguar_jwt/jaguar_jwt.dart'; 6 | 7 | import '../config.dart'; 8 | 9 | class AuthorizationService { 10 | static const String _jwtIssuer = 'eCommers Server'; 11 | 12 | static String signToken(Map user) { 13 | final claimSet = JwtClaim( 14 | issuer: _jwtIssuer, 15 | subject: jsonEncode(user), 16 | issuedAt: DateTime.parse(Config.expirationDate), 17 | ); 18 | 19 | return _encodeTokenData(issueJwtHS256(claimSet, Config.jwtSecret)); 20 | } 21 | 22 | static bool isAuthorized(String authHeader) { 23 | final parts = authHeader.split(' '); 24 | 25 | if (parts == null || parts.length != 2 || parts[0] != 'Bearer') { 26 | return false; 27 | } 28 | 29 | return _isValidToken(parts[1]); 30 | } 31 | 32 | static bool _isValidToken(String token) { 33 | if (extractJwtClaimFrom(token) == null) { 34 | return false; 35 | } 36 | 37 | return true; 38 | } 39 | 40 | static JwtClaim extractJwtClaimFrom(String token) { 41 | try { 42 | return verifyJwtHS256Signature(token, Config.jwtSecret); 43 | } on JwtException { 44 | rethrow; 45 | } 46 | } 47 | 48 | static User getJwtSubject(String authorizationHeader) { 49 | final token = authorizationHeader.split(' ')[1]; 50 | 51 | final jwtClaim = extractJwtClaimFrom(token); 52 | 53 | if (jwtClaim == null) { 54 | return null; 55 | } 56 | 57 | return User.fromJson(jsonDecode(jwtClaim.subject) as Map); 58 | } 59 | 60 | static String _encodeTokenData(String token) { 61 | final loginModel = 62 | LoginModel(token, Config.refreshToken, Config.expirationDate); 63 | 64 | return jsonEncode(loginModel); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ecommers/lib/web_server/services/product_comparator.dart: -------------------------------------------------------------------------------- 1 | import 'package:ecommers/core/models/data_models/index.dart'; 2 | import 'package:ecommers/core/models/sort_type.dart'; 3 | 4 | class ProductComparator { 5 | static int Function(Product, Product) bySortType(SortType sortType) { 6 | switch (sortType) { 7 | case SortType.rate: 8 | return byRate; 9 | case SortType.cost: 10 | return byCost; 11 | case SortType.costDesc: 12 | default: 13 | return byCostDescendant; 14 | } 15 | } 16 | 17 | static int byRate(Product firstProduct, Product secondProduct) { 18 | return secondProduct.rate.compareTo(firstProduct.rate); 19 | } 20 | 21 | static int byCost(Product firstProduct, Product secondProduct) { 22 | return firstProduct.price.compareTo(secondProduct.price); 23 | } 24 | 25 | static int byCostDescendant(Product firstProduct, Product secondProduct) { 26 | return -byCost(firstProduct, secondProduct); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ecommers/runner: -------------------------------------------------------------------------------- 1 | flutter packages pub run build_runner build --delete-conflicting-outputs -------------------------------------------------------------------------------- /ecommers/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:ecommers/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MainApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | --------------------------------------------------------------------------------