From 48eab3308bbe8f07d6459815768afaa8a02420df Mon Sep 17 00:00:00 2001 From: AshAymSal Date: Sun, 23 Jun 2024 23:43:23 +0300 Subject: [PATCH] new --- ecommerce/android/.gitignore | 13 + ecommerce/android/app/build.gradle | 74 +++ ecommerce/android/app/google-services.json | 106 ++++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 47 ++ .../com/example/ecommernce/MainActivity.kt | 6 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + ecommerce/android/build.gradle | 30 ++ ecommerce/android/google-services.json | 106 ++++ ecommerce/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 6 + ecommerce/android/settings.gradle | 11 + ecommerce/ios/.gitignore | 34 ++ ecommerce/ios/Flutter/AppFrameworkInfo.plist | 26 + ecommerce/ios/Flutter/Debug.xcconfig | 1 + ecommerce/ios/Flutter/Release.xcconfig | 1 + .../ios/Runner.xcodeproj/project.pbxproj | 471 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 91 ++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + ecommerce/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 +++++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 ++ .../ios/Runner/Base.lproj/Main.storyboard | 26 + ecommerce/ios/Runner/Info.plist | 45 ++ ecommerce/ios/Runner/Runner-Bridging-Header.h | 1 + ecommerce/lib/cache/sharedPreferences.dart | 32 ++ ecommerce/lib/core/api_services.dart | 95 ++++ ecommerce/lib/core/app_theme.dart | 31 ++ ecommerce/lib/core/errors/exceptions.dart | 5 + ecommerce/lib/core/errors/failures.dart | 18 + ecommerce/lib/core/firebase_services.dart | 69 +++ ecommerce/lib/core/network/network_info.dart | 13 + ecommerce/lib/core/strings/failures.dart | 3 + ecommerce/lib/core/strings/messages.dart | 3 + ecommerce/lib/core/widgets/custom_drawer.dart | 270 ++++++++++ .../lib/core/widgets/loading_widget.dart | 22 + ecommerce/lib/core/widgets/settings_page.dart | 140 ++++++ .../lib/features/auth/auth_provider.dart | 53 ++ ecommerce/lib/features/auth/sign_in_page.dart | 151 ++++++ ecommerce/lib/features/auth/sign_up_page.dart | 74 +++ ecommerce/lib/features/map/location_page.dart | 211 ++++++++ .../products_local_datasource.dart | 61 +++ .../products_remote_datasource.dart | 229 +++++++++ .../products/data/models/product_model.dart | 68 +++ .../repositories/product_repository_imp.dart | 152 ++++++ .../products/domain/entities/product.dart | 51 ++ .../repositories/product_repository.dart | 19 + .../usecases/check_product_is_liked.dart | 17 + .../domain/usecases/get_favorites.dart | 15 + .../domain/usecases/get_populars.dart | 15 + .../usecases/get_products_by_category.dart | 16 + .../usecases/get_products_by_search.dart | 16 + .../usecases/press_favorite_button.dart | 17 + .../bloc/category/category_bloc.dart | 68 +++ .../bloc/category/category_events.dart | 26 + .../bloc/category/category_state.dart | 31 ++ .../bloc/favortites/favorites_bloc.dart | 60 +++ .../bloc/favortites/favorites_events.dart | 28 ++ .../bloc/favortites/favorites_state.dart | 31 ++ .../bloc/one_product/one_product_bloc.dart | 67 +++ .../bloc/one_product/one_product_events.dart | 32 ++ .../bloc/one_product/one_product_state.dart | 29 ++ .../bloc/populars/populars_bloc.dart | 62 +++ .../bloc/populars/populars_events.dart | 14 + .../bloc/populars/populars_state.dart | 31 ++ .../presentation/bloc/search/search_bloc.dart | 59 +++ .../bloc/search/search_events.dart | 21 + .../bloc/search/search_state.dart | 31 ++ .../presentation/pages/category_page.dart | 111 +++++ .../presentation/pages/detalis_page.dart | 211 ++++++++ .../presentation/pages/favorites_page.dart | 90 ++++ .../presentation/pages/home_page.dart | 159 ++++++ .../presentation/pages/search_page.dart | 135 +++++ .../products_by_category_list_widget.dart | 29 ++ .../color_and_quantity_list_widget.dart | 50 ++ .../widgets/detalis_page/colors_widget.dart | 33 ++ .../detalis_page/discription_widget.dart | 26 + .../detalis_page/images_courosel_widget.dart | 80 +++ .../detalis_page/name_and_cost_widget.dart | 25 + .../detalis_page/one_color_widget.dart | 97 ++++ .../widgets/detalis_page/rating_widget.dart | 37 ++ .../detalis_page/request_dialog_widget.dart | 145 ++++++ .../widgets/detalis_page/reviews_widget.dart | 75 +++ .../send_request_button_widget.dart | 32 ++ .../presentation/widgets/favorite_icon.dart | 88 ++++ .../favorites_page/favorites_list_widget.dart | 16 + .../widgets/home_page/category_widget.dart | 40 ++ .../home_page/most_popular_widget.dart | 43 ++ .../home_page/one_product_small_widget.dart | 144 ++++++ .../widgets/message_display_widget.dart | 24 + .../widgets/one_product_big_widget.dart | 135 +++++ .../search_page/search_list_widget.dart | 12 + .../purchase_remote_datasource.dart | 48 ++ .../purchase/data/models/purchase_model.dart | 26 + .../purchase_repository_impl.dart | 35 ++ .../purchase/domain/entites/purchase.dart | 9 + .../repositories/purchase_repository.dart | 8 + .../purchase/domain/usecases/get_sales.dart | 17 + .../presentation/bloc/order/order_cubit.dart | 15 + .../presentation/bloc/order/order_state.dart | 38 ++ .../bloc/purchase/purchase_cubit.dart | 77 +++ .../bloc/purchase/purchase_state.dart | 42 ++ .../presentation/bloc/sales/sales_bloc.dart | 57 +++ .../presentation/bloc/sales/sales_events.dart | 19 + .../presentation/bloc/sales/sales_state.dart | 32 ++ .../presentation/pages/check_out_page.dart | 125 +++++ .../presentation/pages/paypal_payment.dart | 237 +++++++++ .../presentation/pages/sales_page.dart | 97 ++++ .../check_out_page/cross_out_container.dart | 42 ++ .../expandable_tile_widget.dart | 146 ++++++ .../one_item_quantity_widget.dart | 92 ++++ .../pay_with_paypal_button.dart | 69 +++ .../widgets/sales_page/sale_item.dart | 89 ++++ .../widgets/sales_page/sales_list_widget.dart | 20 + .../reviews_remote_datasource.dart | 59 +++ .../reviews/data/models/review_model.dart | 32 ++ .../repositories/review_repository_imp.dart | 49 ++ .../reviews/domain/entities/review.dart | 15 + .../repositories/review_reposaitory.dart | 10 + .../domain/usecases/get_all_reviews.dart | 18 + .../domain/usecases/get_best_review.dart | 17 + .../presentation/bloc/review/review_bloc.dart | 79 +++ .../bloc/review/review_events.dart | 26 + .../bloc/review/review_state.dart | 40 ++ .../presentation/pages/review_page.dart | 55 ++ .../review_page/one_review_widget.dart | 76 +++ .../review_page/reviews_list_widget.dart | 13 + ecommerce/lib/firebase.dart | 199 ++++++++ ecommerce/lib/main.dart | 78 +++ ecommerce/lib/mainPage.dart | 125 +++++ ecommerce/lib/manegerAllProducts.dart | 204 ++++++++ ecommerce/lib/manegerAllProfits.dart | 96 ++++ ecommerce/lib/manegerAllUsers.dart | 90 ++++ ecommerce/lib/manegerMainPage.dart | 40 ++ ecommerce/lib/manegerProductAddOrEdit.dart | 193 +++++++ ecommerce/lib/model/product.dart | 31 ++ ecommerce/lib/model/purchase.dart | 11 + ecommerce/lib/model/review.dart | 10 + ecommerce/lib/model/user.dart | 10 + .../lib/modules/favorites/favoritePage.dart | 57 +++ .../modules/favorites/favoriteProvider.dart | 91 ++++ .../lib/modules/favorites/favoriteWidget.dart | 12 + 176 files changed, 8787 insertions(+) create mode 100644 ecommerce/android/.gitignore create mode 100644 ecommerce/android/app/build.gradle create mode 100644 ecommerce/android/app/google-services.json create mode 100644 ecommerce/android/app/src/debug/AndroidManifest.xml create mode 100644 ecommerce/android/app/src/main/AndroidManifest.xml create mode 100644 ecommerce/android/app/src/main/kotlin/com/example/ecommernce/MainActivity.kt create mode 100644 ecommerce/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 ecommerce/android/app/src/main/res/drawable/launch_background.xml create mode 100644 ecommerce/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 ecommerce/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 ecommerce/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 ecommerce/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 ecommerce/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 ecommerce/android/app/src/main/res/values-night/styles.xml create mode 100644 ecommerce/android/app/src/main/res/values/styles.xml create mode 100644 ecommerce/android/app/src/profile/AndroidManifest.xml create mode 100644 ecommerce/android/build.gradle create mode 100644 ecommerce/android/google-services.json create mode 100644 ecommerce/android/gradle.properties create mode 100644 ecommerce/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 ecommerce/android/settings.gradle create mode 100644 ecommerce/ios/.gitignore create mode 100644 ecommerce/ios/Flutter/AppFrameworkInfo.plist create mode 100644 ecommerce/ios/Flutter/Debug.xcconfig create mode 100644 ecommerce/ios/Flutter/Release.xcconfig create mode 100644 ecommerce/ios/Runner.xcodeproj/project.pbxproj create mode 100644 ecommerce/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 ecommerce/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 ecommerce/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 ecommerce/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 ecommerce/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 ecommerce/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 ecommerce/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 ecommerce/ios/Runner/AppDelegate.swift create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 ecommerce/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 ecommerce/ios/Runner/Base.lproj/Main.storyboard create mode 100644 ecommerce/ios/Runner/Info.plist create mode 100644 ecommerce/ios/Runner/Runner-Bridging-Header.h create mode 100644 ecommerce/lib/cache/sharedPreferences.dart create mode 100644 ecommerce/lib/core/api_services.dart create mode 100644 ecommerce/lib/core/app_theme.dart create mode 100644 ecommerce/lib/core/errors/exceptions.dart create mode 100644 ecommerce/lib/core/errors/failures.dart create mode 100644 ecommerce/lib/core/firebase_services.dart create mode 100644 ecommerce/lib/core/network/network_info.dart create mode 100644 ecommerce/lib/core/strings/failures.dart create mode 100644 ecommerce/lib/core/strings/messages.dart create mode 100644 ecommerce/lib/core/widgets/custom_drawer.dart create mode 100644 ecommerce/lib/core/widgets/loading_widget.dart create mode 100644 ecommerce/lib/core/widgets/settings_page.dart create mode 100644 ecommerce/lib/features/auth/auth_provider.dart create mode 100644 ecommerce/lib/features/auth/sign_in_page.dart create mode 100644 ecommerce/lib/features/auth/sign_up_page.dart create mode 100644 ecommerce/lib/features/map/location_page.dart create mode 100644 ecommerce/lib/features/products/data/datasources/products_local_datasource.dart create mode 100644 ecommerce/lib/features/products/data/datasources/products_remote_datasource.dart create mode 100644 ecommerce/lib/features/products/data/models/product_model.dart create mode 100644 ecommerce/lib/features/products/data/repositories/product_repository_imp.dart create mode 100644 ecommerce/lib/features/products/domain/entities/product.dart create mode 100644 ecommerce/lib/features/products/domain/repositories/product_repository.dart create mode 100644 ecommerce/lib/features/products/domain/usecases/check_product_is_liked.dart create mode 100644 ecommerce/lib/features/products/domain/usecases/get_favorites.dart create mode 100644 ecommerce/lib/features/products/domain/usecases/get_populars.dart create mode 100644 ecommerce/lib/features/products/domain/usecases/get_products_by_category.dart create mode 100644 ecommerce/lib/features/products/domain/usecases/get_products_by_search.dart create mode 100644 ecommerce/lib/features/products/domain/usecases/press_favorite_button.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/category/category_bloc.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/category/category_events.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/category/category_state.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/favortites/favorites_bloc.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/favortites/favorites_events.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/favortites/favorites_state.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/one_product/one_product_bloc.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/one_product/one_product_events.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/one_product/one_product_state.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/populars/populars_bloc.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/populars/populars_events.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/populars/populars_state.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/search/search_bloc.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/search/search_events.dart create mode 100644 ecommerce/lib/features/products/presentation/bloc/search/search_state.dart create mode 100644 ecommerce/lib/features/products/presentation/pages/category_page.dart create mode 100644 ecommerce/lib/features/products/presentation/pages/detalis_page.dart create mode 100644 ecommerce/lib/features/products/presentation/pages/favorites_page.dart create mode 100644 ecommerce/lib/features/products/presentation/pages/home_page.dart create mode 100644 ecommerce/lib/features/products/presentation/pages/search_page.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/category_page/products_by_category_list_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/detalis_page/color_and_quantity_list_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/detalis_page/colors_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/detalis_page/discription_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/detalis_page/images_courosel_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/detalis_page/name_and_cost_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/detalis_page/one_color_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/detalis_page/rating_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/detalis_page/request_dialog_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/detalis_page/reviews_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/detalis_page/send_request_button_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/favorite_icon.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/favorites_page/favorites_list_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/home_page/category_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/home_page/most_popular_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/home_page/one_product_small_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/message_display_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/one_product_big_widget.dart create mode 100644 ecommerce/lib/features/products/presentation/widgets/search_page/search_list_widget.dart create mode 100644 ecommerce/lib/features/purchase/data/datasourcses/purchase_remote_datasource.dart create mode 100644 ecommerce/lib/features/purchase/data/models/purchase_model.dart create mode 100644 ecommerce/lib/features/purchase/data/repositories/purchase_repository_impl.dart create mode 100644 ecommerce/lib/features/purchase/domain/entites/purchase.dart create mode 100644 ecommerce/lib/features/purchase/domain/repositories/purchase_repository.dart create mode 100644 ecommerce/lib/features/purchase/domain/usecases/get_sales.dart create mode 100644 ecommerce/lib/features/purchase/presentation/bloc/order/order_cubit.dart create mode 100644 ecommerce/lib/features/purchase/presentation/bloc/order/order_state.dart create mode 100644 ecommerce/lib/features/purchase/presentation/bloc/purchase/purchase_cubit.dart create mode 100644 ecommerce/lib/features/purchase/presentation/bloc/purchase/purchase_state.dart create mode 100644 ecommerce/lib/features/purchase/presentation/bloc/sales/sales_bloc.dart create mode 100644 ecommerce/lib/features/purchase/presentation/bloc/sales/sales_events.dart create mode 100644 ecommerce/lib/features/purchase/presentation/bloc/sales/sales_state.dart create mode 100644 ecommerce/lib/features/purchase/presentation/pages/check_out_page.dart create mode 100644 ecommerce/lib/features/purchase/presentation/pages/paypal_payment.dart create mode 100644 ecommerce/lib/features/purchase/presentation/pages/sales_page.dart create mode 100644 ecommerce/lib/features/purchase/presentation/widgets/check_out_page/cross_out_container.dart create mode 100644 ecommerce/lib/features/purchase/presentation/widgets/check_out_page/expandable_tile_widget.dart create mode 100644 ecommerce/lib/features/purchase/presentation/widgets/check_out_page/one_item_quantity_widget.dart create mode 100644 ecommerce/lib/features/purchase/presentation/widgets/check_out_page/pay_with_paypal_button.dart create mode 100644 ecommerce/lib/features/purchase/presentation/widgets/sales_page/sale_item.dart create mode 100644 ecommerce/lib/features/purchase/presentation/widgets/sales_page/sales_list_widget.dart create mode 100644 ecommerce/lib/features/reviews/data/datasources/reviews_remote_datasource.dart create mode 100644 ecommerce/lib/features/reviews/data/models/review_model.dart create mode 100644 ecommerce/lib/features/reviews/data/repositories/review_repository_imp.dart create mode 100644 ecommerce/lib/features/reviews/domain/entities/review.dart create mode 100644 ecommerce/lib/features/reviews/domain/repositories/review_reposaitory.dart create mode 100644 ecommerce/lib/features/reviews/domain/usecases/get_all_reviews.dart create mode 100644 ecommerce/lib/features/reviews/domain/usecases/get_best_review.dart create mode 100644 ecommerce/lib/features/reviews/presentation/bloc/review/review_bloc.dart create mode 100644 ecommerce/lib/features/reviews/presentation/bloc/review/review_events.dart create mode 100644 ecommerce/lib/features/reviews/presentation/bloc/review/review_state.dart create mode 100644 ecommerce/lib/features/reviews/presentation/pages/review_page.dart create mode 100644 ecommerce/lib/features/reviews/presentation/widgets/review_page/one_review_widget.dart create mode 100644 ecommerce/lib/features/reviews/presentation/widgets/review_page/reviews_list_widget.dart create mode 100644 ecommerce/lib/firebase.dart create mode 100644 ecommerce/lib/main.dart create mode 100644 ecommerce/lib/mainPage.dart create mode 100644 ecommerce/lib/manegerAllProducts.dart create mode 100644 ecommerce/lib/manegerAllProfits.dart create mode 100644 ecommerce/lib/manegerAllUsers.dart create mode 100644 ecommerce/lib/manegerMainPage.dart create mode 100644 ecommerce/lib/manegerProductAddOrEdit.dart create mode 100644 ecommerce/lib/model/product.dart create mode 100644 ecommerce/lib/model/purchase.dart create mode 100644 ecommerce/lib/model/review.dart create mode 100644 ecommerce/lib/model/user.dart create mode 100644 ecommerce/lib/modules/favorites/favoritePage.dart create mode 100644 ecommerce/lib/modules/favorites/favoriteProvider.dart create mode 100644 ecommerce/lib/modules/favorites/favoriteWidget.dart diff --git a/ecommerce/android/.gitignore b/ecommerce/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/ecommerce/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/ecommerce/android/app/build.gradle b/ecommerce/android/app/build.gradle new file mode 100644 index 0000000..950c494 --- /dev/null +++ b/ecommerce/android/app/build.gradle @@ -0,0 +1,74 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'com.google.gms.google-services' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 33 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.ecommernce" + minSdkVersion 20 + targetSdkVersion 33 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + multiDexEnabled true + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation platform('com.google.firebase:firebase-bom:29.0.3') + implementation 'com.google.firebase:firebase-analytics' + implementation 'com.android.support:multidex:1.0.3' + +} diff --git a/ecommerce/android/app/google-services.json b/ecommerce/android/app/google-services.json new file mode 100644 index 0000000..07ed91d --- /dev/null +++ b/ecommerce/android/app/google-services.json @@ -0,0 +1,106 @@ +{ + "project_info": { + "project_number": "874948994538", + "firebase_url": "https://gogo-379dc-default-rtdb.firebaseio.com", + "project_id": "gogo-379dc", + "storage_bucket": "gogo-379dc.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:874948994538:android:a54451d1bb7f67221cfe93", + "android_client_info": { + "package_name": "com.example.ecommernce" + } + }, + "oauth_client": [ + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBg5U8_TEc9K5GWeG9Nl4CRbM_UcrQRfRg" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:874948994538:android:b8d6c59db46eba7b1cfe93", + "android_client_info": { + "package_name": "com.example.flutter_app" + } + }, + "oauth_client": [ + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBg5U8_TEc9K5GWeG9Nl4CRbM_UcrQRfRg" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:874948994538:android:467eece349a027fe1cfe93", + "android_client_info": { + "package_name": "com.example.go2" + } + }, + "oauth_client": [ + { + "client_id": "874948994538-8i9n078k85t5u7er149oh87hl87smdld.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.example.go2", + "certificate_hash": "4c612133220383ed1c8125c7bee54db6c75d817d" + } + }, + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBg5U8_TEc9K5GWeG9Nl4CRbM_UcrQRfRg" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/ecommerce/android/app/src/debug/AndroidManifest.xml b/ecommerce/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..3e2cc58 --- /dev/null +++ b/ecommerce/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/ecommerce/android/app/src/main/AndroidManifest.xml b/ecommerce/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d50ac46 --- /dev/null +++ b/ecommerce/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ecommerce/android/app/src/main/kotlin/com/example/ecommernce/MainActivity.kt b/ecommerce/android/app/src/main/kotlin/com/example/ecommernce/MainActivity.kt new file mode 100644 index 0000000..fb49399 --- /dev/null +++ b/ecommerce/android/app/src/main/kotlin/com/example/ecommernce/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.ecommernce + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/ecommerce/android/app/src/main/res/drawable-v21/launch_background.xml b/ecommerce/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/ecommerce/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/ecommerce/android/app/src/main/res/drawable/launch_background.xml b/ecommerce/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/ecommerce/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/ecommerce/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/ecommerce/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/ecommerce/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/ecommerce/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/ecommerce/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ecommerce/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/ecommerce/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/ecommerce/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/ecommerce/android/app/src/main/res/values-night/styles.xml b/ecommerce/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..449a9f9 --- /dev/null +++ b/ecommerce/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/ecommerce/android/app/src/main/res/values/styles.xml b/ecommerce/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..d74aa35 --- /dev/null +++ b/ecommerce/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/ecommerce/android/app/src/profile/AndroidManifest.xml b/ecommerce/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..3e2cc58 --- /dev/null +++ b/ecommerce/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/ecommerce/android/build.gradle b/ecommerce/android/build.gradle new file mode 100644 index 0000000..18dd133 --- /dev/null +++ b/ecommerce/android/build.gradle @@ -0,0 +1,30 @@ +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.google.gms:google-services:4.3.10' + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/ecommerce/android/google-services.json b/ecommerce/android/google-services.json new file mode 100644 index 0000000..07ed91d --- /dev/null +++ b/ecommerce/android/google-services.json @@ -0,0 +1,106 @@ +{ + "project_info": { + "project_number": "874948994538", + "firebase_url": "https://gogo-379dc-default-rtdb.firebaseio.com", + "project_id": "gogo-379dc", + "storage_bucket": "gogo-379dc.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:874948994538:android:a54451d1bb7f67221cfe93", + "android_client_info": { + "package_name": "com.example.ecommernce" + } + }, + "oauth_client": [ + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBg5U8_TEc9K5GWeG9Nl4CRbM_UcrQRfRg" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:874948994538:android:b8d6c59db46eba7b1cfe93", + "android_client_info": { + "package_name": "com.example.flutter_app" + } + }, + "oauth_client": [ + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBg5U8_TEc9K5GWeG9Nl4CRbM_UcrQRfRg" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:874948994538:android:467eece349a027fe1cfe93", + "android_client_info": { + "package_name": "com.example.go2" + } + }, + "oauth_client": [ + { + "client_id": "874948994538-8i9n078k85t5u7er149oh87hl87smdld.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.example.go2", + "certificate_hash": "4c612133220383ed1c8125c7bee54db6c75d817d" + } + }, + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBg5U8_TEc9K5GWeG9Nl4CRbM_UcrQRfRg" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "874948994538-nb7r6bkctjgpe53d5627dniqqpr485od.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/ecommerce/android/gradle.properties b/ecommerce/android/gradle.properties new file mode 100644 index 0000000..94adc3a --- /dev/null +++ b/ecommerce/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/ecommerce/android/gradle/wrapper/gradle-wrapper.properties b/ecommerce/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..bc6a58a --- /dev/null +++ b/ecommerce/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/ecommerce/android/settings.gradle b/ecommerce/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/ecommerce/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/ecommerce/ios/.gitignore b/ecommerce/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/ecommerce/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/ecommerce/ios/Flutter/AppFrameworkInfo.plist b/ecommerce/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..8d4492f --- /dev/null +++ b/ecommerce/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 9.0 + + diff --git a/ecommerce/ios/Flutter/Debug.xcconfig b/ecommerce/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/ecommerce/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/ecommerce/ios/Flutter/Release.xcconfig b/ecommerce/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/ecommerce/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/ecommerce/ios/Runner.xcodeproj/project.pbxproj b/ecommerce/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..3687d04 --- /dev/null +++ b/ecommerce/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,471 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.ecommernce; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.ecommernce; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.ecommernce; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ecommerce/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ecommerce/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/ecommerce/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ecommerce/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ecommerce/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ecommerce/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ecommerce/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ecommerce/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ecommerce/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ecommerce/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ecommerce/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..a28140c --- /dev/null +++ b/ecommerce/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ecommerce/ios/Runner.xcworkspace/contents.xcworkspacedata b/ecommerce/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/ecommerce/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ecommerce/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ecommerce/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ecommerce/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ecommerce/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ecommerce/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ecommerce/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ecommerce/ios/Runner/AppDelegate.swift b/ecommerce/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/ecommerce/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 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 literal 0 HcmV?d00001 diff --git a/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 zcmVjJBgitF5mAp-i>4+KS_oR{|13AP->1TD4=w)g|)JHOx|a2Wk1Va z!k)vP$UcQ#mdj%wNQoaJ!w>jv_6&JPyutpQps?s5dmDQ>`%?Bvj>o<%kYG!YW6H-z zu`g$@mp`;qDR!51QaS}|ZToSuAGcJ7$2HF0z`ln4t!#Yg46>;vGG9N9{V@9z#}6v* zfP?}r6b{*-C*)(S>NECI_E~{QYzN5SXRmVnP<=gzP+_Sp(Aza_hKlZ{C1D&l*(7IKXxQC1Z9#6wx}YrGcn~g%;icdw>T0Rf^w0{ z$_wn1J+C0@!jCV<%Go5LA45e{5gY9PvZp8uM$=1}XDI+9m7!A95L>q>>oe0$nC->i zeexUIvq%Uk<-$>DiDb?!In)lAmtuMWxvWlk`2>4lNuhSsjAf2*2tjT`y;@d}($o)S zn(+W&hJ1p0xy@oxP%AM15->wPLp{H!k)BdBD$toBpJh+crWdsNV)qsHaqLg2_s|Ih z`8E9z{E3sA!}5aKu?T!#enD(wLw?IT?k-yWVHZ8Akz4k5(TZJN^zZgm&zM28sfTD2BYJ|Fde3Xzh;;S` z=GXTnY4Xc)8nYoz6&vF;P7{xRF-{|2Xs5>a5)@BrnQ}I(_x7Cgpx#5&Td^4Q9_FnQ zX5so*;#8-J8#c$OlA&JyPp$LKUhC~-e~Ij!L%uSMu!-VZG7Hx-L{m2DVR2i=GR(_% zCVD!4N`I)&Q5S`?P&fQZ=4#Dgt_v2-DzkT}K(9gF0L(owe-Id$Rc2qZVLqI_M_DyO z9@LC#U28_LU{;wGZ&))}0R2P4MhajKCd^K#D+JJ&JIXZ_p#@+7J9A&P<0kdRujtQ_ zOy>3=C$kgi6$0pW06KaLz!21oOryKM3ZUOWqppndxfH}QpgjEJ`j7Tzn5bk6K&@RA?vl##y z$?V~1E(!wB5rH`>3nc&@)|#<1dN2cMzzm=PGhQ|Yppne(C-Vlt450IXc`J4R0W@I7 zd1e5uW6juvO%ni(WX7BsKx3MLngO7rHO;^R5I~0^nE^9^E_eYLgiR9&KnJ)pBbfno zSVnW$0R+&6jOOsZ82}nJ126+c|%svPo;TeUku<2G7%?$oft zyaO;tVo}(W)VsTUhq^XmFi#2z%-W9a{7mXn{uzivYQ_d6b7VJG{77naW(vHt-uhnY zVN#d!JTqVh(7r-lhtXVU6o})aZbDt_;&wJVGl2FKYFBFpU-#9U)z#(A%=IVnqytR$SY-sO( z($oNE09{D^@OuYPz&w~?9>Fl5`g9u&ecFGhqX=^#fmR=we0CJw+5xna*@oHnkahk+ z9aWeE3v|An+O5%?4fA&$Fgu~H_YmqR!yIU!bFCk4!#pAj%(lI(A5n)n@Id#M)O9Yx zJU9oKy{sRAIV3=5>(s8n{8ryJ!;ho}%pn6hZKTKbqk=&m=f*UnK$zW3YQP*)pw$O* zIfLA^!-bmBl6%d_n$#tP8Zd_(XdA*z*WH|E_yILwjtI~;jK#v-6jMl^?<%Y%`gvpwv&cFb$||^v4D&V=aNy?NGo620jL3VZnA%s zH~I|qPzB~e(;p;b^gJr7Ure#7?8%F0m4vzzPy^^(q4q1OdthF}Fi*RmVZN1OwTsAP zn9CZP`FazX3^kG(KodIZ=Kty8DLTy--UKfa1$6XugS zk%6v$Kmxt6U!YMx0JQ)0qX*{CXwZZk$vEROidEc7=J-1;peNat!vS<3P-FT5po>iE z!l3R+<`#x|+_hw!HjQGV=8!q|76y8L7N8gP3$%0kfush|u0uU^?dKBaeRSBUpOZ0c z62;D&Mdn2}N}xHRFTRI?zRv=>=AjHgH}`2k4WK=#AHB)UFrR-J87GgX*x5fL^W2#d z=(%K8-oZfMO=i{aWRDg=FX}UubM4eotRDcn;OR#{3q=*?3mE3_oJ-~prjhxh%PgQT zyn)Qozaq0@o&|LEgS{Ind4Swsr;b`u185hZPOBLL<`d2%^Yp1?oL)=jnLi;Zo0ZDliTtQ^b5SmfIMe{T==zZkbvn$KTQGlbG8w}s@M3TZnde;1Am46P3juKb zl9GU&3F=q`>j!`?SyH#r@O59%@aMX^rx}Nxe<>NqpUp5=lX1ojGDIR*-D^SDuvCKF z?3$xG(gVUsBERef_YjPFl^rU9EtD{pt z0CXwpN7BN3!8>hajGaTVk-wl=9rxmfWtIhC{mheHgStLi^+Nz12a?4r(fz)?3A%at zMlvQmL<2-R)-@G1wJ0^zQK%mR=r4d{Y3fHp){nWXUL#|CqXl(+v+qDh>FkF9`eWrW zfr^D%LNfOcTNvtx0JXR35J0~Jpi2#P3Q&80w+nqNfc}&G0A~*)lGHKv=^FE+b(37|)zL;KLF>oiGfb(?&1 zV3XRu!Sw>@quKiab%g6jun#oZ%!>V#A%+lNc?q>6+VvyAn=kf_6z^(TZUa4Eelh{{ zqFX-#dY(EV@7l$NE&kv9u9BR8&Ojd#ZGJ6l8_BW}^r?DIS_rU2(XaGOK z225E@kH5Opf+CgD^{y29jD4gHbGf{1MD6ggQ&%>UG4WyPh5q_tb`{@_34B?xfSO*| zZv8!)q;^o-bz`MuxXk*G^}(6)ACb@=Lfs`Hxoh>`Y0NE8QRQ!*p|SH@{r8=%RKd4p z+#Ty^-0kb=-H-O`nAA3_6>2z(D=~Tbs(n8LHxD0`R0_ATFqp-SdY3(bZ3;VUM?J=O zKCNsxsgt@|&nKMC=*+ZqmLHhX1KHbAJs{nGVMs6~TiF%Q)P@>!koa$%oS zjXa=!5>P`vC-a}ln!uH1ooeI&v?=?v7?1n~P(wZ~0>xWxd_Aw;+}9#eULM7M8&E?Y zC-ZLhi3RoM92SXUb-5i-Lmt5_rfjE{6y^+24`y$1lywLyHO!)Boa7438K4#iLe?rh z2O~YGSgFUBH?og*6=r9rme=peP~ah`(8Zt7V)j5!V0KPFf_mebo3z95U8(up$-+EA^9dTRLq>Yl)YMBuch9%=e5B`Vnb>o zt03=kq;k2TgGe4|lGne&zJa~h(UGutjP_zr?a7~#b)@15XNA>Dj(m=gg2Q5V4-$)D|Q9}R#002ovPDHLkV1o7DH3k3x literal 0 HcmV?d00001 diff --git a/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ecommerce/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/ecommerce/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +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. \ No newline at end of file diff --git a/ecommerce/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ecommerce/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/ecommerce/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ecommerce/ios/Runner/Base.lproj/Main.storyboard b/ecommerce/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/ecommerce/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ecommerce/ios/Runner/Info.plist b/ecommerce/ios/Runner/Info.plist new file mode 100644 index 0000000..f4b45ac --- /dev/null +++ b/ecommerce/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ecommernce + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/ecommerce/ios/Runner/Runner-Bridging-Header.h b/ecommerce/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/ecommerce/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/ecommerce/lib/cache/sharedPreferences.dart b/ecommerce/lib/cache/sharedPreferences.dart new file mode 100644 index 0000000..333478b --- /dev/null +++ b/ecommerce/lib/cache/sharedPreferences.dart @@ -0,0 +1,32 @@ +import 'package:shared_preferences/shared_preferences.dart'; + +class sharedPreferences { + static SharedPreferences? preferences; + static Future init() async { + preferences = await SharedPreferences.getInstance(); + } + + static setEmail(String a) { + preferences!.setString("email", a); + } + + static String getEmail() { + return preferences!.getString("email") ?? ""; + } + + static setPassword(String a) { + preferences!.setString("password", a); + } + + static String getPassword() { + return preferences!.getString("password") ?? ""; + } + + static setLogin(String a) { + preferences!.setString("login", a); + } + + static String getLogin() { + return preferences!.getString("login") ?? ""; + } +} diff --git a/ecommerce/lib/core/api_services.dart b/ecommerce/lib/core/api_services.dart new file mode 100644 index 0000000..7bb87c4 --- /dev/null +++ b/ecommerce/lib/core/api_services.dart @@ -0,0 +1,95 @@ +import 'package:http/http.dart' as http; +import 'dart:async'; +import 'dart:convert' as convert; +import 'package:http_auth/http_auth.dart'; + +class Services { + String domain = + "https://api.sandbox.paypal.com"; // for sandbox mode// String domain = "https://api.paypal.com"; // for production mode + + String clientId = + 'Ad6jE1kpqdSUjNLIxJV4iIo4c43EmiLWeNGXa8VcwUKy6TlDxCum2GzIAQ9w-IXsDfI6vua9r1uOW68O'; + String secret = + 'EG1_0a0g_Q7667ReMUuYpBgJOHTD0COG7zuPx5JRDAy2B6ovaC2CpWPUaKGhF0ENOMMMHfNLT3m64XbD'; + + // for getting the access token from Paypal + Future getAccessToken() async { + try { + var client = BasicAuthClient(clientId, secret); + var response = await client.post( + Uri.parse('$domain/v1/oauth2/token?grant_type=client_credentials')); + if (response.statusCode == 200) { + final body = convert.jsonDecode(response.body); + print("getAccessToken " + body["access_token"]); + return body["access_token"]; + } + return null; + } catch (e) { + rethrow; + } + } + + // for creating the payment request with Paypals + Future?> createPaypalPayment( + transactions, accessToken) async { + print('createPaypalPayment '); + try { + print('createPaypalPayment in'); + var response = await http.post(Uri.parse("$domain/v1/payments/payment"), + body: convert.jsonEncode(transactions), + headers: { + "content-type": "application/json", + 'Authorization': 'Bearer ' + accessToken + }); + + final body = convert.jsonDecode(response.body); + //print(+ body); + if (response.statusCode == 201) { + if (body["links"] != null && body["links"].length > 0) { + List links = body["links"]; + + String executeUrl = ""; + String approvalUrl = ""; + final item = links.firstWhere((o) => o["rel"] == "approval_url", + orElse: () => null); + if (item != null) { + approvalUrl = item["href"]; + } + final item1 = links.firstWhere((o) => o["rel"] == "execute", + orElse: () => null); + if (item1 != null) { + executeUrl = item1["href"]; + } + print(executeUrl + " kkk " + approvalUrl); + return {"executeUrl": executeUrl, "approvalUrl": approvalUrl}; + } + return null; + } else { + throw Exception(body["message"]); + } + } catch (e) { + print(e); + } + return null; + } + + // for executing the payment transaction + Future executePayment(url, payerId, accessToken) async { + try { + var response = await http.post(Uri.parse(url), + body: convert.jsonEncode({"payer_id": payerId}), + headers: { + "content-type": "application/json", + 'Authorization': 'Bearer ' + accessToken + }); + + final body = convert.jsonDecode(response.body); + if (response.statusCode == 200) { + return body["id"]; + } + return null; + } catch (e) { + rethrow; + } + } +} diff --git a/ecommerce/lib/core/app_theme.dart b/ecommerce/lib/core/app_theme.dart new file mode 100644 index 0000000..2d27ea9 --- /dev/null +++ b/ecommerce/lib/core/app_theme.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +final primaryColor = Color(0xff082659); +final secondaryColor = Color(0xff51eec2); + +final appTheme = ThemeData( + appBarTheme: AppBarTheme( + backgroundColor: primaryColor, + centerTitle: true, + ), + brightness: Brightness.light, + primaryColor: primaryColor, + colorScheme: ColorScheme.light( + primary: primaryColor, + ), + progressIndicatorTheme: ProgressIndicatorThemeData(color: primaryColor), + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: primaryColor, + foregroundColor: secondaryColor, + ), + inputDecorationTheme: InputDecorationTheme( + floatingLabelStyle: TextStyle(color: primaryColor), + iconColor: secondaryColor, + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: secondaryColor), + borderRadius: BorderRadius.circular(8), + ), + border: OutlineInputBorder( + borderSide: BorderSide(color: primaryColor), + borderRadius: BorderRadius.circular(8), + ))); diff --git a/ecommerce/lib/core/errors/exceptions.dart b/ecommerce/lib/core/errors/exceptions.dart new file mode 100644 index 0000000..78acdf3 --- /dev/null +++ b/ecommerce/lib/core/errors/exceptions.dart @@ -0,0 +1,5 @@ +class ServerException implements Exception {} + +class EmptyCacheException implements Exception {} + +class OfflineException implements Exception {} diff --git a/ecommerce/lib/core/errors/failures.dart b/ecommerce/lib/core/errors/failures.dart new file mode 100644 index 0000000..993eb9e --- /dev/null +++ b/ecommerce/lib/core/errors/failures.dart @@ -0,0 +1,18 @@ +import 'package:equatable/equatable.dart'; + +abstract class Failure extends Equatable {} + +class OfflineFailure extends Failure { + @override + List get props => []; +} + +class ServerFailure extends Failure { + @override + List get props => []; +} + +class EmptyCacheFailure extends Failure { + @override + List get props => []; +} diff --git a/ecommerce/lib/core/firebase_services.dart b/ecommerce/lib/core/firebase_services.dart new file mode 100644 index 0000000..d4984cb --- /dev/null +++ b/ecommerce/lib/core/firebase_services.dart @@ -0,0 +1,69 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:intl/intl.dart'; + +class firebaseServices { + firebaseServices(); + + void increaseTimes(List pur) { + for (var p in pur) { + int purTimes = int.parse(p.quantity!); + + FirebaseFirestore.instance + .collection("products") + .doc(p.p!.id!) + .get() + .then((value) { + var data = value.data() as Map; + int oldTimes = int.parse(data['times']); + int newTimes = purTimes += oldTimes; + FirebaseFirestore.instance + .collection("products") + .doc(p.p!.id!) + .update({'times': newTimes.toString()}); + }); + } + } + + void addToSales(String id, List pur) { + String daydate = DateFormat("yyyy-MM-dd").format(DateTime.now()); + String dattime = DateFormat("HH:mm:ss").format(DateTime.now()); + for (Purchase r in pur) { + FirebaseFirestore.instance + .collection("users") + .doc(id) + .collection('sales') + .add({ + "id": r.p!.id, + "name": r.p!.name, + "cost": r.p!.cost, + "quantity": r.quantity, + "image": r.p!.images![0], + "daytime": dattime, + "daydate": daydate, + }); + } + } + + void addToProfits(List pur) { + int total = 0; + for (var p in pur) { + int purCost = int.parse(p.p!.cost!) * int.parse(p.quantity!); + total += purCost; + print("${p.p!.name!} " + purCost.toString()); + // print("${p.p!.name!} newProfits " + newProfits.toString()); + } + + CollectionReference ref3 = FirebaseFirestore.instance.collection("profits"); + ref3.get().then((value) { + final prof = value.docs[0]["total"]; + final profid = value.docs[0]["id"]; + + int curprof = int.parse(prof); + print("curprof " + curprof.toString()); + int plusprof = curprof + total; + print("plusprof " + plusprof.toString()); + ref3.doc(profid).update({"total": plusprof.toString()}); + }); + } +} diff --git a/ecommerce/lib/core/network/network_info.dart b/ecommerce/lib/core/network/network_info.dart new file mode 100644 index 0000000..dfb666a --- /dev/null +++ b/ecommerce/lib/core/network/network_info.dart @@ -0,0 +1,13 @@ +import 'package:internet_connection_checker/internet_connection_checker.dart'; + +abstract class NetworkInfo { + Future get isConnected; +} + +class NetworkInfoImpl implements NetworkInfo { + final InternetConnectionChecker connectionChecker; + + NetworkInfoImpl(this.connectionChecker); + @override + Future get isConnected => connectionChecker.hasConnection; +} diff --git a/ecommerce/lib/core/strings/failures.dart b/ecommerce/lib/core/strings/failures.dart new file mode 100644 index 0000000..a5abb20 --- /dev/null +++ b/ecommerce/lib/core/strings/failures.dart @@ -0,0 +1,3 @@ +const String SERVER_FAILURE_MESSAGE = 'Please try again later .'; +const String EMPTY_CACHE_FAILURE_MESSAGE = 'No Data'; +const String OFFLINE_FAILURE_MESSAGE = 'Please Check your Internet Connection'; diff --git a/ecommerce/lib/core/strings/messages.dart b/ecommerce/lib/core/strings/messages.dart new file mode 100644 index 0000000..21f738e --- /dev/null +++ b/ecommerce/lib/core/strings/messages.dart @@ -0,0 +1,3 @@ +const ADD_SUCCESS_MESSAGE = "Post Added Successfully"; +const DELETE_SUCCESS_MESSAGE = "Post Deleted Successfully"; +const UPDATE_SUCCESS_MESSAGE = "Post Updated Successfully"; diff --git a/ecommerce/lib/core/widgets/custom_drawer.dart b/ecommerce/lib/core/widgets/custom_drawer.dart new file mode 100644 index 0000000..d6ae357 --- /dev/null +++ b/ecommerce/lib/core/widgets/custom_drawer.dart @@ -0,0 +1,270 @@ +import 'dart:math' show pi; +import 'package:ecommernce/core/widgets/settings_page.dart'; +import 'package:ecommernce/mainPage.dart'; +import 'package:flutter/material.dart'; + +class CustomDrawerController { + int s = 0; + Function open = () {}; + Function close = () {}; + Function toggle = (Function f) { + print("togggg "); + f(); + }; + bool isOpen = true; + + ValueNotifier? stateNotifier; + + CustomDrawerController(this.open, this.close, this.toggle, this.isOpen); + /*void setToggle(Function f, int fq) { + print("setTooogle"); + toggle = f; + s = fq; + print(s); + }*/ +} + +class CustomDrawer extends StatefulWidget { + CustomDrawer({ + //required this.controller, + //required this.menuScreen, + // required this.mainScreen, + this.slideWidth = 275.0, + this.borderRadius = 16.0, + this.angle = -12.0, + this.backgroundColor = Colors.white, + this.showShadow = false, + this.openCurve, + this.closeCurve, + }) : assert(angle <= 0.0 && angle >= -30.0); + + //final CustomDrawerController controller; + + // final Widget menuScreen; + // final Widget mainScreen; + final double slideWidth; + final double borderRadius; + final double angle; + final Color backgroundColor; + final bool showShadow; + final Curve? openCurve; + final Curve? closeCurve; + + @override + _CustomDrawerState createState() => _CustomDrawerState(); + + /// static function to provide the drawer state + // static State? of(BuildContext context) { + // return context.findAncestorStateOfType>(); + //} + + /// Static function to determine the device text direction RTL/LTR + static bool isRTL(BuildContext context) { + return false; + // return !Provider.of(context, listen: false).isLtr; + } +} + +class _CustomDrawerState extends State + with SingleTickerProviderStateMixin { + final Curve _scaleDownCurve = Interval(0.0, 0.3, curve: Curves.easeOut); + final Curve _scaleUpCurve = Interval(0.0, 1.0, curve: Curves.easeOut); + final Curve _slideOutCurve = Interval(0.0, 1.0, curve: Curves.easeOut); + final Curve _slideInCurve = + Interval(0.0, 1.0, curve: Curves.easeOut); // Curves.bounceOut + + /// check the slide direction + /// + + late CustomDrawerController controller; + + AnimationController? _animationController; + DrawerState _state = DrawerState.closed; + + double get _percentOpen => _animationController!.value; + + open() { + print("ooop"); + + _animationController!.forward(); + } + + close() { + print("cloooos"); + + _animationController!.reverse(); + } + + toggle() { + print("toooot"); + if (_state == DrawerState.open) { + close(); + } else if (_state == DrawerState.closed) { + open(); + } + } + + bool isOpen() => + _state == DrawerState.open /*|| _state == DrawerState.opening*/; + + /// Drawer state + ValueNotifier? stateNotifier; + + @override + void initState() { + super.initState(); + + stateNotifier = ValueNotifier(_state); + + _animationController = AnimationController( + vsync: this, duration: const Duration(milliseconds: 500)) + ..addStatusListener((AnimationStatus status) { + switch (status) { + case AnimationStatus.forward: + _state = DrawerState.opening; + _updateStatusNotifier(); + break; + case AnimationStatus.reverse: + _state = DrawerState.closing; + _updateStatusNotifier(); + break; + case AnimationStatus.completed: + _state = DrawerState.open; + _updateStatusNotifier(); + break; + case AnimationStatus.dismissed: + _state = DrawerState.closed; + _updateStatusNotifier(); + break; + } + }); + + /// assign controller function to the widget methods + controller = CustomDrawerController(open, close, toggle, isOpen()); + /*if (widget.controller != null) { + print("init toggle"); + + widget.controller.open = open(); + widget.controller.close = close(); + widget.controller.toggle = toggle(); + // widget.controller.setToggle(toggle, 2); + widget.controller.isOpen = isOpen(); + widget.controller.stateNotifier = stateNotifier; + }*/ + } + + _updateStatusNotifier() { + stateNotifier!.value = _state; + print(_state); + } + + @override + void dispose() { + _animationController!.dispose(); + super.dispose(); + } + + Widget _zoomAndSlideContent(Widget container, BuildContext context, + {double? angle, double? scale, double slide = 0}) { + var slidePercent, scalePercent; + + /// determine current slide percent based on the MenuStatus + switch (_state) { + case DrawerState.closed: + slidePercent = 0.0; + scalePercent = 0.0; + break; + case DrawerState.open: + slidePercent = 1.0; + scalePercent = 1.0; + break; + case DrawerState.opening: + slidePercent = + (widget.openCurve ?? _slideOutCurve).transform(_percentOpen); + scalePercent = _scaleDownCurve.transform(_percentOpen); + break; + case DrawerState.closing: + slidePercent = + (widget.closeCurve ?? _slideInCurve).transform(_percentOpen); + scalePercent = _scaleUpCurve.transform(_percentOpen); + break; + } + + final int _rtlSlide = CustomDrawer.isRTL(context) ? -1 : 1; + + final slideAmount = (widget.slideWidth - slide) * slidePercent * _rtlSlide; + final contentScale = (scale ?? 1.0) - (0.4 * scalePercent); + final cornerRadius = widget.borderRadius * _percentOpen; + final rotationAngle = + (((angle ?? widget.angle) * pi * _rtlSlide) / 180) * _percentOpen; + + return Transform( + transform: Matrix4.translationValues(slideAmount, 0, 0) + ..rotateZ(rotationAngle) + ..scale(contentScale, contentScale), + alignment: Alignment.centerLeft, + child: ClipRRect( + borderRadius: BorderRadius.circular(cornerRadius), + child: container, + ), + ); + } + + @override + Widget build(BuildContext context) { + final slidePercent = CustomDrawer.isRTL(context) + ? MediaQuery.of(context).size.width * .1 + : 15.0; + + return Stack( + children: [ + GestureDetector( + child: slSettingsPage(controller), //widget.menuScreen, + onPanUpdate: (details) { + final bool _rtl = CustomDrawer.isRTL(context); + if (details.delta.dx < -6 && !_rtl || + details.delta.dx < 6 && _rtl) { + //print("asdasdasd"); + toggle(); + } + }, + ), + if (widget.showShadow) ...[ + /// Displaying the first shadow + AnimatedBuilder( + animation: _animationController!, + builder: (_, w) => _zoomAndSlideContent(w!, context, + angle: (widget.angle == 0.0) ? 0.0 : widget.angle - 8, + scale: .9, + slide: slidePercent * 2), + child: Container( + color: widget.backgroundColor.withAlpha(31), + ), + ), + + /// Displaying the second shadow + AnimatedBuilder( + animation: _animationController!, + builder: (_, w) => _zoomAndSlideContent(w!, context, + angle: (widget.angle == 0.0) ? 0.0 : widget.angle - 4.0, + scale: .95, + slide: slidePercent), + child: Container( + color: widget.backgroundColor, + ), + ) + ], + + /// Displaying the main screen + AnimatedBuilder( + animation: _animationController!, + builder: (_, w) => _zoomAndSlideContent(w!, context), + child: slMainPage(controller) //widget.mainScreen, + ), + ], + ); + } +} + +/// Drawer State enum +enum DrawerState { opening, closing, open, closed } diff --git a/ecommerce/lib/core/widgets/loading_widget.dart b/ecommerce/lib/core/widgets/loading_widget.dart new file mode 100644 index 0000000..e814060 --- /dev/null +++ b/ecommerce/lib/core/widgets/loading_widget.dart @@ -0,0 +1,22 @@ +import '../app_theme.dart'; +import 'package:flutter/material.dart'; + +class LoadingWidget extends StatelessWidget { + const LoadingWidget({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: Center( + child: SizedBox( + height: 30, + width: 30, + child: CircularProgressIndicator( + color: secondaryColor, + ), + ), + ), + ); + } +} diff --git a/ecommerce/lib/core/widgets/settings_page.dart b/ecommerce/lib/core/widgets/settings_page.dart new file mode 100644 index 0000000..958783c --- /dev/null +++ b/ecommerce/lib/core/widgets/settings_page.dart @@ -0,0 +1,140 @@ +import 'package:ecommernce/core/widgets/custom_drawer.dart'; +import 'package:ecommernce/features/auth/sign_in_page.dart'; +import 'package:ecommernce/features/map/location_page.dart'; +import 'package:ecommernce/features/products/presentation/pages/favorites_page.dart'; +import 'package:ecommernce/features/purchase/presentation/pages/check_out_page.dart'; +import 'package:ecommernce/features/purchase/presentation/pages/sales_page.dart'; +import 'package:ecommernce/features/auth/auth_provider.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; + +class slSettingsPage extends StatelessWidget { + CustomDrawerController drawerController; + slSettingsPage(this.drawerController, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return sfSettingsPage(drawerController); + } +} + +class sfSettingsPage extends StatefulWidget { + final CustomDrawerController drawerController; + const sfSettingsPage(this.drawerController, {Key? key}) : super(key: key); + + @override + State createState() => _stateSettingsPage(); +} + +class _stateSettingsPage extends State { + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + if (widget.drawerController.isOpen) { + widget.drawerController.toggle; + print(widget.drawerController.s); + return false; + } else { + return true; + } + }, + child: Scaffold( + body: Container( + height: MediaQuery.of(context).size.height - 60, + width: MediaQuery.of(context).size.width, + color: Color(0xffd3faff), + child: Column( + children: [ + SizedBox( + height: 60, + ), + FirebaseAuth.instance.currentUser == null + ? GestureDetector( + child: ListTile( + leading: Icon(Icons.login), + title: Text("LogIn"), + ), + onTap: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return signIn(); + })); + }, + ) + : Container( + child: Text( + FirebaseAuth.instance.currentUser!.email!, + style: TextStyle(fontSize: 20), + ), + ), + SizedBox(height: 40), + GestureDetector( + child: ListTile( + leading: Icon(Icons.wallet), + title: Text("My Orders"), + ), + onTap: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return CheckOutPage(); + })); + }, + ), + GestureDetector( + child: ListTile( + leading: Icon(Icons.favorite), + title: Text("My Favorites"), + ), + onTap: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return slFavoritePage(); + })); + }, + ), + GestureDetector( + child: ListTile( + leading: Icon(Icons.sell), + title: Text("My Sales History"), + ), + onTap: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return slSalePage(); + })); + }, + ), + ListTile( + leading: Icon(Icons.search), + title: Text("My Browser History"), + ), + GestureDetector( + child: ListTile( + leading: Icon(Icons.sell), + title: Text("Get your shipping location"), + ), + onTap: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return SimpleMap(); + })); + }, + ), + SizedBox(height: 50), + FirebaseAuth.instance.currentUser != null + ? GestureDetector( + child: ListTile( + leading: Icon(Icons.logout), + title: Text("Log Out"), + ), + onTap: () { + signInProvider.getRead(context).signOut(); + }, + ) + : Container() + ], + )), + )); + } +} diff --git a/ecommerce/lib/features/auth/auth_provider.dart b/ecommerce/lib/features/auth/auth_provider.dart new file mode 100644 index 0000000..881e141 --- /dev/null +++ b/ecommerce/lib/features/auth/auth_provider.dart @@ -0,0 +1,53 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:ecommernce/cache/sharedPreferences.dart'; +import 'package:provider/provider.dart'; + +class signInProvider extends ChangeNotifier { + static signInProvider getWatch(BuildContext context) { + //print("watch"); + return context.watch(); + } + + static signInProvider getRead(BuildContext context) { + //print("read"); + return context.read(); + } + + final FirebaseAuth firebaseAuth; + + signInProvider(this.firebaseAuth); + + Stream get authStateChenges { + return firebaseAuth.authStateChanges(); + } + + Future signIn({String? email, String? password}) async { + try { + await firebaseAuth.signInWithEmailAndPassword( + email: email!, password: password!); + sharedPreferences.setEmail(email); + sharedPreferences.setPassword(password); + return "Signed In"; + } on FirebaseAuthException catch (e) { + return e.message!; + } + } + + Future signOut() async { + await firebaseAuth.signOut(); + } + + Future signUp({String? email, String? password}) async { + try { + await firebaseAuth.createUserWithEmailAndPassword( + email: email!, password: password!); + CollectionReference ref = FirebaseFirestore.instance.collection("users"); + ref.doc(email).set({"email": email, "password": password}); + return "Signed Up"; + } on FirebaseAuthException catch (e) { + return e.message!; + } + } +} diff --git a/ecommerce/lib/features/auth/sign_in_page.dart b/ecommerce/lib/features/auth/sign_in_page.dart new file mode 100644 index 0000000..cb1ad50 --- /dev/null +++ b/ecommerce/lib/features/auth/sign_in_page.dart @@ -0,0 +1,151 @@ +import 'package:ecommernce/features/auth/sign_up_page.dart'; +import 'package:ecommernce/manegerMainPage.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:ecommernce/cache/sharedPreferences.dart'; +import 'package:ecommernce/features/auth/auth_provider.dart'; + +class signIn extends StatefulWidget { + @override + State createState() { + return signInState(); + } +} + +class signInState extends State { + TextEditingController email = TextEditingController(); + TextEditingController password = TextEditingController(); + + @override + void initState() { + super.initState(); + email.text = sharedPreferences.getEmail(); + password.text = sharedPreferences.getPassword(); + /*String isLoged = sharedPreferences.getLogin(); + if (isLoged == "1") { + + String logpass = sharedPreferences.getPassword(); + signInProvider + .getRead(context) + .signIn(email: logemail.trim(), password: logpass.trim()); + */ + } + + @override + Widget build(BuildContext context) { + final totalHeight = MediaQuery.of(context).size.height; + final totalWidth = MediaQuery.of(context).size.width; + return Scaffold( + body: SingleChildScrollView( + child: Container( + height: totalHeight, + width: totalWidth, + color: Color(0xffd3faff), + child: Column( + children: [ + SizedBox( + height: totalHeight / 6, + ), + Container( + child: Text( + "Sign In", + style: TextStyle(fontSize: 25, fontFamily: "New"), + ), + ), + SizedBox( + height: totalHeight / 20, + ), + Container( + padding: EdgeInsets.symmetric(horizontal: totalWidth / 30), + color: Colors.white, + width: totalWidth / 1.2, + child: TextField( + controller: email, + decoration: InputDecoration(border: InputBorder.none), + ), + ), + SizedBox( + height: totalHeight / 30, + ), + Container( + padding: EdgeInsets.symmetric(horizontal: totalWidth / 30), + color: Colors.white, + width: totalWidth / 1.2, + child: TextField( + controller: password, + decoration: InputDecoration(border: InputBorder.none), + obscureText: true, + ), + ), + SizedBox( + height: totalHeight / 20, + ), + Container( + width: totalWidth / 3, + height: totalHeight / 20, + child: ElevatedButton( + child: Text( + "sign in", + style: TextStyle(fontSize: 17, fontFamily: "New"), + ), + onPressed: () { + signInProvider + .getRead(context) + .signIn( + email: email.text.trim(), + password: password.text.trim()) + .then((value) { + Navigator.of(context).pop(); + }); + }, + ), + ), + SizedBox( + height: totalHeight / 20, + ), + Container( + width: totalWidth / 2.4, + child: Row( + children: [ + Text( + "Sign up here : ", + style: TextStyle(fontFamily: "New"), + ), + RichText( + text: TextSpan( + style: + TextStyle(color: Colors.blue, fontFamily: "New"), + text: "Sign Up", + recognizer: TapGestureRecognizer() + ..onTap = () { + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return signUp(); + })); + }), + ) + ], + ), + ), + SizedBox( + height: totalHeight / 3, + ), + Container( + child: ElevatedButton( + child: Text( + "Maneger", + style: TextStyle(fontFamily: "New"), + ), + onPressed: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return slManegerHome(); + })); + }, + ), + ), + ], + )), + )); + } +} diff --git a/ecommerce/lib/features/auth/sign_up_page.dart b/ecommerce/lib/features/auth/sign_up_page.dart new file mode 100644 index 0000000..db1f313 --- /dev/null +++ b/ecommerce/lib/features/auth/sign_up_page.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:ecommernce/features/auth/auth_provider.dart'; + +class signUp extends StatelessWidget { + TextEditingController email = TextEditingController(); + TextEditingController password = TextEditingController(); + @override + Widget build(BuildContext context) { + final totalHeight = MediaQuery.of(context).size.height; + final totalWidth = MediaQuery.of(context).size.width; + return Scaffold( + body: Container( + height: totalHeight, + width: totalWidth, + color: Color(0xffd3faff), + child: Column( + children: [ + SizedBox( + height: totalHeight / 6, + ), + Container( + child: Text( + "Sign Up", + style: TextStyle(fontSize: 25, fontFamily: "New"), + ), + ), + SizedBox( + height: totalHeight / 20, + ), + Container( + padding: EdgeInsets.symmetric(horizontal: totalWidth / 30), + color: Colors.white, + width: totalWidth / 1.2, + child: TextField( + controller: email, + decoration: InputDecoration(border: InputBorder.none), + ), + ), + SizedBox( + height: totalHeight / 30, + ), + Container( + padding: EdgeInsets.symmetric(horizontal: totalWidth / 30), + color: Colors.white, + width: totalWidth / 1.2, + child: TextField( + controller: password, + decoration: InputDecoration(border: InputBorder.none), + ), + ), + SizedBox( + height: totalHeight / 20, + ), + Container( + width: totalWidth / 3, + height: totalHeight / 20, + child: ElevatedButton( + child: Text( + "sign up", + style: TextStyle(fontSize: 15, fontFamily: "New"), + ), + onPressed: () { + signInProvider.getRead(context).signUp( + email: email.text.trim(), + password: password.text.trim()); + Navigator.pop(context); + }, + ), + ), + ], + )), + ); + } +} diff --git a/ecommerce/lib/features/map/location_page.dart b/ecommerce/lib/features/map/location_page.dart new file mode 100644 index 0000000..1a116f1 --- /dev/null +++ b/ecommerce/lib/features/map/location_page.dart @@ -0,0 +1,211 @@ + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:location/location.dart'; + +class SimpleMap extends StatefulWidget { + @override + _SimpleMapState createState() => _SimpleMapState(); +} + +class _SimpleMapState extends State { + static final LatLng center = LatLng(31.947351, 35.227163); + Map markers = {}; + MarkerId? selectedMarker; + int _markerIdCounter = 1; + LatLng? markerPosition; + + double lang = center.latitude; + double long = center.longitude; + + static final CameraPosition _kInitialPosition = + CameraPosition(target: center, zoom: 11.0, tilt: 0, bearing: 0); + GoogleMapController? _controller; + + Future onMapCreated(GoogleMapController controller) async { + _controller = controller; + } + + @override + Widget build(BuildContext context) { + final MarkerId? selectedId = selectedMarker; + return Scaffold( + floatingActionButton: FloatingActionButton(onPressed: () { + _currentLocation(); + }), + appBar: AppBar( + title: Text('Google Map'), + ), + body: Stack(children: [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: GoogleMap( + initialCameraPosition: _kInitialPosition, + onMapCreated: onMapCreated, + myLocationEnabled: true, + markers: Set.of(markers.values), + trafficEnabled: true, + onTap: _handleTap, + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: _add, + child: const Text('Add'), + ), + TextButton( + onPressed: + selectedId == null ? null : () => _remove(selectedId), + child: const Text('Remove'), + ), + ], + ), + ]) + ]) + /* ,*/ + ); + } + + void _currentLocation() async { + // Create a map controller + final GoogleMapController controller = await _controller!; + LocationData? currentLocation; + var location = new Location(); + try { + // Find and store your location in a variable + currentLocation = await location.getLocation(); + } on Exception { + currentLocation = null; + } + + // Move the map camera to the found location using the controller + controller.animateCamera(CameraUpdate.newCameraPosition( + CameraPosition( + bearing: 0, + target: LatLng(currentLocation!.latitude!, currentLocation.longitude!), + zoom: 17.0, + ), + )); + } + + Set _createMarker() { + return { + Marker( + markerId: MarkerId("marker_1"), + position: center, + infoWindow: InfoWindow(title: 'Marker 1'), + rotation: 90), + Marker( + markerId: MarkerId("marker_2"), + position: LatLng(18.997962200185533, 72.8379758747611), + ), + }; + } + + _handleTap(LatLng point) { + setState(() { + lang = point.latitude; + long = point.longitude; + }); + } + + void _onMarkerTapped(MarkerId markerId) { + final Marker? tappedMarker = markers[markerId]; + if (tappedMarker != null) { + setState(() { + final MarkerId? previousMarkerId = selectedMarker; + if (previousMarkerId != null && markers.containsKey(previousMarkerId)) { + final Marker resetOld = markers[previousMarkerId]! + .copyWith(iconParam: BitmapDescriptor.defaultMarker); + markers[previousMarkerId] = resetOld; + } + selectedMarker = markerId; + final Marker newMarker = tappedMarker.copyWith( + iconParam: BitmapDescriptor.defaultMarkerWithHue( + BitmapDescriptor.hueGreen, + ), + ); + markers[markerId] = newMarker; + + markerPosition = null; + }); + } + } + + Future _onMarkerDrag(MarkerId markerId, LatLng newPosition) async { + setState(() { + markerPosition = newPosition; + }); + } + + Future _onMarkerDragEnd(MarkerId markerId, LatLng newPosition) async { + final Marker? tappedMarker = markers[markerId]; + if (tappedMarker != null) { + setState(() { + markerPosition = null; + }); + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + actions: [ + TextButton( + child: const Text('OK'), + onPressed: () => Navigator.of(context).pop(), + ) + ], + content: Padding( + padding: const EdgeInsets.symmetric(vertical: 66), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('Old position: ${tappedMarker.position}'), + Text('New position: $newPosition'), + ], + ))); + }); + } + } + + void _add() { + final int markerCount = markers.length; + print('markerCount' + markerCount.toString()); + + if (markerCount == 12) { + return; + } + + final String markerIdVal = 'marker_id_$_markerIdCounter'; + _markerIdCounter++; + final MarkerId markerId = MarkerId(markerIdVal); + + final Marker marker = Marker( + markerId: markerId, + position: LatLng( + lang, + long, + ), + infoWindow: InfoWindow(title: markerIdVal, snippet: '*'), + onTap: () => _onMarkerTapped(markerId), + onDragEnd: (LatLng position) => _onMarkerDragEnd(markerId, position), + onDrag: (LatLng position) => _onMarkerDrag(markerId, position), + ); + + setState(() { + markers[markerId] = marker; + }); + } + + void _remove(MarkerId markerId) { + setState(() { + if (markers.containsKey(markerId)) { + markers.remove(markerId); + } + }); + } +} diff --git a/ecommerce/lib/features/products/data/datasources/products_local_datasource.dart b/ecommerce/lib/features/products/data/datasources/products_local_datasource.dart new file mode 100644 index 0000000..37f99dd --- /dev/null +++ b/ecommerce/lib/features/products/data/datasources/products_local_datasource.dart @@ -0,0 +1,61 @@ + +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/features/products/data/models/product_model.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +abstract class ProductsLocalDataSource { + Future> getCachedFavorites(); + Future> getCachedSales(); + Future cacheFavorites(List productModels); +} + +const CACHED_FAVORITES = "CACHED_FAVORITES"; +const CACHED_SALES = "CACHED_SALES"; + +class ProductsLocalDataSourceImpl implements ProductsLocalDataSource { + @override + Future cacheFavorites(List productModels) { + // TODO: implement cacheFavorites + print("asD"); + throw UnimplementedError(); + } + + @override + Future> getCachedFavorites() { + // TODO: implement getCachedFavorites + throw UnimplementedError(); + } + + @override + Future> getCachedSales() { + // TODO: implement getCachedFavorites + throw UnimplementedError(); + } + // SharedPreferences sharedPreferences; + + //ProductsLocalDataSourceImpl({required this.sharedPreferences}); + /* @override + Future cacheFavorites(List postModels) { + List postModelsToJson = postModels + .map>((postModel) => postModel.toJson()) + .toList(); + sharedPreferences.setString( + CACHED_FAVORITES, json.encode(postModelsToJson)); + return Future.value(unit); + } + + @override + Future> getCachedFavorites() { + final jsonString = sharedPreferences.getString(CACHED_FAVORITES); + if (jsonString != null) { + List decodeJsonData = json.decode(jsonString); + List jsonToPostModels = decodeJsonData + .map( + (jsonPostModel) => ProductModel.fromJson(jsonPostModel)) + .toList(); + return Future.value(jsonToPostModels); + } else { + throw EmptyCacheException(); + } + }*/ +} diff --git a/ecommerce/lib/features/products/data/datasources/products_remote_datasource.dart b/ecommerce/lib/features/products/data/datasources/products_remote_datasource.dart new file mode 100644 index 0000000..caf9752 --- /dev/null +++ b/ecommerce/lib/features/products/data/datasources/products_remote_datasource.dart @@ -0,0 +1,229 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/features/products/data/models/product_model.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; + +abstract class ProductsRemoteDataSource { + Future> getPopular(); + Future> getFavorites({required String userId}); + Future> getProductsByCategory({required String category}); + Future> getProductsBySearch({required String searchText}); + Future removeFromFavoritesAsId(int id); + Future pressFavoriteButton( + {required Product product, + required bool isLiked, + required String userId}); + Future checkProductIsLiked( + {required String userId, required Product product}); +} + +class ProductsRemoteDataSourceImpl implements ProductsRemoteDataSource { + ProductsRemoteDataSourceImpl(); + + @override + Future> getFavorites({String? userId}) async { + CollectionReference ref = FirebaseFirestore.instance.collection("products"); + CollectionReference ref2 = FirebaseFirestore.instance + .collection("users") + .doc(userId) + .collection("favorites"); + QuerySnapshot qsshid = await ref2.get(); // هان برجع كبشة documents + List listid = qsshid.docs; // وهان بنحطهم ك list + print(userId!); + + List ids = []; + listid.forEach((elementt) { + String id = elementt["id"]; + ids.add(id); + }); + List re = await gdd(ids, userId); + print("iddddss" + re.length.toString()); + return re; + + //print(favorites.length); + } + + Future> gdd(List ids, String userId) async { + List favorites = []; + CollectionReference ref = FirebaseFirestore.instance.collection("products"); + CollectionReference ref2 = FirebaseFirestore.instance + .collection("users") + .doc(userId) + .collection("favorites"); + + for (var elemente in ids) { + QuerySnapshot qsshpro = await ref.where("id", isEqualTo: elemente).get(); + if (qsshpro.docs.isEmpty) { + QuerySnapshot qsshproo = + await ref2.where("id", isEqualTo: elemente).get(); + String id = qsshproo.docs[0]["fav id"]; + ref2.doc(id).delete(); + } else { + final element = qsshpro.docs[0]; + ProductModel toAdd = ProductModel( + name: element["name"], + id: element["id"], + type: element["type"], + times: element["times"], + cost: element["cost"], + images: element["images"], + description: element["description"], + sizes: element['sizes'], + colors: element['colors'], + rating: element['rating'], + ); + favorites.add(toAdd); + } + } + return favorites; + } + + @override + Future pressFavoriteButton( + {required String userId, + required bool isLiked, + required Product product}) async { + CollectionReference ref = FirebaseFirestore.instance + .collection("users") + .doc(userId) + .collection("favorites"); + if (isLiked) { + var s = await ref.where("id", isEqualTo: product.id!).get(); + QueryDocumentSnapshot qd = s.docs[0]; + var del = await ref.doc(qd.id).delete(); + // icon = Icons.favorite_border; + // iconColor = Colors.black; + return false; + // favoriteProvider.getRead(context).removeFromFavoritesAsId(pro); + } else { + var s = await ref.where("id", isEqualTo: product.id!).get(); + var ad = await ref.add({ + "id": product.id!, + }); + var upd = await ref.doc(ad.id).update({"fav id": ad.id}); + //icon = Icons.favorite; + // iconColor = Colors.red; + return true; + // favoriteProvider.getRead(context).addToFavorites(pro); + // notifyListeners(); + } + } + + @override + Future> getPopular() async { + List mostPopular = []; + CollectionReference ref = FirebaseFirestore.instance.collection("products"); + QuerySnapshot qssh = await ref + .orderBy("times", descending: true) + .limit(5) + .get(); // هان برجع كبشة documents + List listdocs = qssh.docs; // وهان بنحطهم ك list + listdocs.forEach((element) { + ProductModel toAdd = ProductModel( + name: element["name"], + id: element["id"], + type: element["type"], + times: element["times"], + cost: element["cost"], + images: element["images"], + description: element["description"], + sizes: element['sizes'], + colors: element['colors'], + rating: element['rating']); + mostPopular.add(toAdd); + /*try { + notifyListeners(); + } catch (e) { + print(e); + }*/ + }); + return mostPopular; + } + + @override + Future removeFromFavoritesAsId(int id) { + // TODO: implement removeFromFavoritesAsId + throw UnimplementedError(); + } + + @override + Future> getProductsByCategory( + {required String category}) async { + List products = []; + CollectionReference ref1 = + FirebaseFirestore.instance.collection("products"); + QuerySnapshot qssh = await ref1.where("type", isEqualTo: category).get(); + List listdocs = qssh.docs; // وهان بنحطهم ك list + //print(category); + + listdocs.forEach((element) { + ProductModel toAdd = ProductModel( + name: element["name"], + id: element["id"], + type: element["type"], + times: element["times"], + cost: element["cost"], + images: element["images"], + description: element["description"], + sizes: element['sizes'], + colors: element['colors'], + rating: element['rating'], + ); + products.add(toAdd); + }); + return products; + } + + @override + Future checkProductIsLiked( + {required String userId, required Product product}) async { + CollectionReference ref = FirebaseFirestore.instance + .collection("users") + .doc(userId) + .collection("favorites"); + var list = await ref.where("id", isEqualTo: product.id!).get(); + if (list.size > 0) { + // icon = Icons.favorite; + //iconColor = Colors.red; + return true; + } else { + // icon = Icons.favorite_border; + // iconColor = Colors.black; + return false; + } + } + + @override + Future> getProductsBySearch( + {required String searchText}) async { + List products = []; + CollectionReference ref1 = + FirebaseFirestore.instance.collection("products"); + if (!searchText.isEmpty) { + QuerySnapshot qssh = await ref1 + .where("name", + isGreaterThanOrEqualTo: searchText, + isLessThan: searchText.substring(0, searchText.length - 1) + + String.fromCharCode( + searchText.codeUnitAt(searchText.length - 1) + 1)) + .get(); + List listdocs = qssh.docs; // وهان بنحطهم ك list + listdocs.forEach((element) async { + ProductModel toAdd = ProductModel( + name: element["name"], + id: element["id"], + type: element["type"], + times: element["times"], + cost: element["cost"], + images: element["images"], + description: element["description"], + sizes: element['sizes'], + colors: element['colors'], + rating: element['rating'], + ); + products.add(toAdd); + }); + } + return products; + } +} diff --git a/ecommerce/lib/features/products/data/models/product_model.dart b/ecommerce/lib/features/products/data/models/product_model.dart new file mode 100644 index 0000000..5cab25d --- /dev/null +++ b/ecommerce/lib/features/products/data/models/product_model.dart @@ -0,0 +1,68 @@ +import 'package:ecommernce/features/products/domain/entities/product.dart'; + +class ProductModel extends Product { + ProductModel( + {String? id, + String? name, + String? type, + String? cost, + String? description, + List? images, + String? times, + String? daytime, + String? daydate, + List? sizes, + List? colors, + List? reviews, + String? rating}) + : super( + id: id, + name: name, + type: type, + cost: cost, + description: description, + images: images, + times: times, + daytime: daytime, + daydate: daydate, + sizes: sizes, + colors: colors, + rating: rating, + reviews: reviews); + + factory ProductModel.fromJson(Map json) { + return ProductModel( + id: json['id'], + name: json['name'], + type: json['type'], + cost: json['cost'], + description: json['description'], + images: json['images'], + times: json['times'], + daydate: json['daydate'], + daytime: json['daytime'], + sizes: json['sizes'], + colors: json['colors'], + reviews: json['revies'], + rating: json['rating'], + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'type': type, + 'cost': cost, + 'description': description, + 'images': images, + 'times': times, + 'daydate': daydate, + 'daytime': daytime, + 'sizes': sizes, + 'colors': colors, + 'reviews': reviews, + 'rating': rating + }; + } +} diff --git a/ecommerce/lib/features/products/data/repositories/product_repository_imp.dart b/ecommerce/lib/features/products/data/repositories/product_repository_imp.dart new file mode 100644 index 0000000..83c300f --- /dev/null +++ b/ecommerce/lib/features/products/data/repositories/product_repository_imp.dart @@ -0,0 +1,152 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/exceptions.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/features/products/data/datasources/products_local_datasource.dart'; +import 'package:ecommernce/features/products/data/datasources/products_remote_datasource.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/repositories/product_repository.dart'; +import 'package:firebase_auth/firebase_auth.dart'; + +class ProductsRepositoryImpl implements ProductsRepository { + final ProductsRemoteDataSource remoteDataSource; + final ProductsLocalDataSource localDataSource; + final NetworkInfo networkInfo; + ProductsRepositoryImpl({ + required this.remoteDataSource, + required this.localDataSource, + required this.networkInfo, + }); + + @override + Future>> getFavorites( + {required String userId}) async { + if (await networkInfo.isConnected) { + try { + final remoteFavorites = + await remoteDataSource.getFavorites(userId: userId); + //print('getFavorites remote' + remoteFavorites.length.toString()); + // localDataSource.cacheFavorites(remotePosts); + return Right(remoteFavorites); + } on ServerException { + return Left(ServerFailure()); + } + } else { + try { + final localPosts = await localDataSource.getCachedFavorites(); + return Right(localPosts); + } on EmptyCacheException { + return Left(EmptyCacheFailure()); + } + } + } + + @override + Future>> getPopular() async { + if (await networkInfo.isConnected) { + try { + final remotePopulars = await remoteDataSource.getPopular(); + print('getPopulars remote' + remotePopulars.length.toString()); + // localDataSource.cacheFavorites(remotePosts); + return Right(remotePopulars); + } on ServerException { + return Left(ServerFailure()); + } + } else { + try { + final localPosts = await localDataSource.getCachedFavorites(); + return Right(localPosts); + } on EmptyCacheException { + return Left(EmptyCacheFailure()); + } + } + } + + @override + Future> removeFromFavoritesAsId(int id) { + // TODO: implement removeFromFavoritesAsId + throw UnimplementedError(); + } + + @override + Future>> getProductsByCategory( + {required String category}) async { + if (await networkInfo.isConnected) { + try { + final remoteProductsByCategory = + await remoteDataSource.getProductsByCategory(category: category); + // print('getPopulars remote' + remoteProductsByCategory.length.toString()); + // localDataSource.cacheFavorites(remotePosts); + return Right(remoteProductsByCategory); + } on ServerException { + return Left(ServerFailure()); + } + } else { + try { + final localPosts = await localDataSource.getCachedFavorites(); + return Right(localPosts); + } on EmptyCacheException { + return Left(EmptyCacheFailure()); + } + } + } + + @override + Future> pressFavoriteButton( + {required Product product, required bool isLiked}) async { + if (await networkInfo.isConnected) { + try { + final press = await remoteDataSource.pressFavoriteButton( + product: product, + isLiked: isLiked, + userId: FirebaseAuth.instance.currentUser!.email!); + //print('getPopulars remote' + remotePopulars.length.toString()); + // localDataSource.cacheFavorites(remotePosts); + return Right(press); + } on ServerException { + return Left(ServerFailure()); + } + } else { + print("not connected"); + return Right(false); + } + } + + @override + Future> checkProductIsLiked( + {required String userId, required Product product}) async { + if (await networkInfo.isConnected) { + try { + final remoteIsLiked = await remoteDataSource.checkProductIsLiked( + product: product, userId: userId); + //print('getPopulars remote' + remotePopulars.length.toString()); + // localDataSource.cacheFavorites(remotePosts); + return Right(remoteIsLiked); + } on ServerException { + return Left(ServerFailure()); + } + } else { + print("not connected"); + return Right(false); + } + } + + @override + Future>> getProductsBySearch( + {required String searchText}) async { + if (await networkInfo.isConnected) { + try { + final remoteProductsByCategory = + await remoteDataSource.getProductsBySearch(searchText: searchText); + // print('getPopulars remote' + remoteProductsByCategory.length.toString()); + // localDataSource.cacheFavorites(remotePosts); + return Right(remoteProductsByCategory); + } on ServerException { + return Left(ServerFailure()); + } + } else { + print("not connected"); + return Right([]); + } + } +} diff --git a/ecommerce/lib/features/products/domain/entities/product.dart b/ecommerce/lib/features/products/domain/entities/product.dart new file mode 100644 index 0000000..5bd60d1 --- /dev/null +++ b/ecommerce/lib/features/products/domain/entities/product.dart @@ -0,0 +1,51 @@ +import 'package:equatable/equatable.dart'; + +class Product extends Equatable { + String? id; + String? name; + String? type; + String? cost; + String? description; + List? images; + String? times; + String? daytime; + String? daydate; + List? sizes; + List? colors; + List? reviews; + String? rating; + + Product({ + this.id, + this.name, + this.type, + this.cost, + this.description, + this.images, + this.times, + this.daydate, + this.daytime, + this.colors, + this.sizes, + this.reviews, + this.rating, + }); + + @override + // TODO: implement props + List get props => [ + id, + name, + type, + cost, + description, + images, + times, + daydate, + daytime, + colors, + sizes, + reviews, + rating, + ]; +} diff --git a/ecommerce/lib/features/products/domain/repositories/product_repository.dart b/ecommerce/lib/features/products/domain/repositories/product_repository.dart new file mode 100644 index 0000000..e3146ff --- /dev/null +++ b/ecommerce/lib/features/products/domain/repositories/product_repository.dart @@ -0,0 +1,19 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; + +abstract class ProductsRepository { + Future>> getPopular(); + Future>> getFavorites({required String userId}); + Future>> getProductsByCategory( + {required String category}); + Future>> getProductsBySearch( + {required String searchText}); + Future> removeFromFavoritesAsId(int id); + Future> pressFavoriteButton( + {required Product product, required bool isLiked}); + Future> checkProductIsLiked( + {required String userId, required Product product}); + //Future deletePost(int id); + //Future updatePost(Product product); +} diff --git a/ecommerce/lib/features/products/domain/usecases/check_product_is_liked.dart b/ecommerce/lib/features/products/domain/usecases/check_product_is_liked.dart new file mode 100644 index 0000000..0d327d4 --- /dev/null +++ b/ecommerce/lib/features/products/domain/usecases/check_product_is_liked.dart @@ -0,0 +1,17 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/repositories/product_repository.dart'; + +class CheckProductIsLikedUsecase { + final ProductsRepository repository; + + CheckProductIsLikedUsecase({required this.repository}); + + Future> call( + {required String userId, required Product product}) async { + print('CheckProductIsLikedUsecase'); + return await repository.checkProductIsLiked( + userId: userId, product: product); + } +} diff --git a/ecommerce/lib/features/products/domain/usecases/get_favorites.dart b/ecommerce/lib/features/products/domain/usecases/get_favorites.dart new file mode 100644 index 0000000..e84b5fd --- /dev/null +++ b/ecommerce/lib/features/products/domain/usecases/get_favorites.dart @@ -0,0 +1,15 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/repositories/product_repository.dart'; + +class GetFavoritesUsecase { + final ProductsRepository repository; + + GetFavoritesUsecase({required this.repository}); + + Future>> call({required String userId}) async { + print('GetFavoritesUsecase'); + return await repository.getFavorites(userId: userId); + } +} diff --git a/ecommerce/lib/features/products/domain/usecases/get_populars.dart b/ecommerce/lib/features/products/domain/usecases/get_populars.dart new file mode 100644 index 0000000..d06d65c --- /dev/null +++ b/ecommerce/lib/features/products/domain/usecases/get_populars.dart @@ -0,0 +1,15 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/repositories/product_repository.dart'; + +class GetPopularsUsecase { + final ProductsRepository repository; + + GetPopularsUsecase({required this.repository}); + + Future>> call() async { + print('GetFavoritesUsecase'); + return await repository.getPopular(); + } +} diff --git a/ecommerce/lib/features/products/domain/usecases/get_products_by_category.dart b/ecommerce/lib/features/products/domain/usecases/get_products_by_category.dart new file mode 100644 index 0000000..7d77607 --- /dev/null +++ b/ecommerce/lib/features/products/domain/usecases/get_products_by_category.dart @@ -0,0 +1,16 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/repositories/product_repository.dart'; + +class GetProductsByCategoryUsecase { + final ProductsRepository repository; + + GetProductsByCategoryUsecase({required this.repository}); + + Future>> call( + {required String category}) async { + print('GetProductsByCategoryUsecase'); + return await repository.getProductsByCategory(category: category); + } +} diff --git a/ecommerce/lib/features/products/domain/usecases/get_products_by_search.dart b/ecommerce/lib/features/products/domain/usecases/get_products_by_search.dart new file mode 100644 index 0000000..e4798ee --- /dev/null +++ b/ecommerce/lib/features/products/domain/usecases/get_products_by_search.dart @@ -0,0 +1,16 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/repositories/product_repository.dart'; + +class GetProductsBySearchUsecase { + final ProductsRepository repository; + + GetProductsBySearchUsecase({required this.repository}); + + Future>> call( + {required String searchText}) async { + print('GetProductsByCategoryUsecase'); + return await repository.getProductsBySearch(searchText: searchText); + } +} diff --git a/ecommerce/lib/features/products/domain/usecases/press_favorite_button.dart b/ecommerce/lib/features/products/domain/usecases/press_favorite_button.dart new file mode 100644 index 0000000..d75336f --- /dev/null +++ b/ecommerce/lib/features/products/domain/usecases/press_favorite_button.dart @@ -0,0 +1,17 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/repositories/product_repository.dart'; + +class PressFavoriteButtonUsecase { + final ProductsRepository repository; + + PressFavoriteButtonUsecase({required this.repository}); + + Future> call( + {required Product product, required bool isLiked}) async { + print('PressFavoriteButtonUsecase'); + return await repository.pressFavoriteButton( + product: product, isLiked: isLiked); + } +} diff --git a/ecommerce/lib/features/products/presentation/bloc/category/category_bloc.dart b/ecommerce/lib/features/products/presentation/bloc/category/category_bloc.dart new file mode 100644 index 0000000..c9c60da --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/category/category_bloc.dart @@ -0,0 +1,68 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/core/strings/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_favorites.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_populars.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_products_by_category.dart'; +import 'package:ecommernce/features/products/presentation/bloc/category/category_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/category/category_state.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_state.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_state.dart'; +import 'package:equatable/equatable.dart'; + +import 'package:flutter_bloc/flutter_bloc.dart'; + +class CategoryBloc extends Bloc { + final GetProductsByCategoryUsecase getProductsByCategory; + CategoryBloc({ + required this.getProductsByCategory, + }) : super(CategoryInitial()) { + on((event, emit) async { + if (event is GetProductsByCategoryEvent) { + emit(LoadingProductsByCategoryState()); + + final failureOrPosts = + await getProductsByCategory(category: event.category); + emit(_mapFailureOrPostsToState( + failureOrPosts as Either>)); + } else if (event is RefreshProductsByCategoryEvent) { + emit(LoadingProductsByCategoryState()); + + final failureOrPosts = + await getProductsByCategory(category: event.category); + emit(_mapFailureOrPostsToState( + failureOrPosts as Either>)); + } + }); + } + + CategoryState _mapFailureOrPostsToState( + Either> either) { + return either.fold((failure) { + print("fffff"); + return ErrorProductsByCategoryState( + message: _mapFailureToMessage(failure)); + }, (productsByCategory) { + //print("yyyyyyy " + productsByCategory.length.toString()); + return LoadedProductsByCategoryState( + productsByCategory: productsByCategory, + ); + }); + } + + String _mapFailureToMessage(Failure failure) { + switch (failure.runtimeType) { + case ServerFailure: + return SERVER_FAILURE_MESSAGE; + case EmptyCacheFailure: + return EMPTY_CACHE_FAILURE_MESSAGE; + case OfflineFailure: + return OFFLINE_FAILURE_MESSAGE; + default: + return "Unexpected Error , Please try again later ."; + } + } +} diff --git a/ecommerce/lib/features/products/presentation/bloc/category/category_events.dart b/ecommerce/lib/features/products/presentation/bloc/category/category_events.dart new file mode 100644 index 0000000..086b518 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/category/category_events.dart @@ -0,0 +1,26 @@ +import 'package:equatable/equatable.dart'; + +abstract class CategoryEvent extends Equatable { + const CategoryEvent(); + + @override + List get props => []; +} + +class GetProductsByCategoryEvent extends CategoryEvent { + final String category; + + GetProductsByCategoryEvent({required this.category}); + + @override + List get props => [category]; +} + +class RefreshProductsByCategoryEvent extends CategoryEvent { + final String category; + + RefreshProductsByCategoryEvent({required this.category}); + + @override + List get props => [category]; +} diff --git a/ecommerce/lib/features/products/presentation/bloc/category/category_state.dart b/ecommerce/lib/features/products/presentation/bloc/category/category_state.dart new file mode 100644 index 0000000..b46adfa --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/category/category_state.dart @@ -0,0 +1,31 @@ +//part of 'favorites_bloc.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; + +abstract class CategoryState { + const CategoryState(); + + @override + List get props => []; +} + +class CategoryInitial extends CategoryState {} + +class LoadingProductsByCategoryState extends CategoryState {} + +class LoadedProductsByCategoryState extends CategoryState { + final List productsByCategory; + + LoadedProductsByCategoryState({required this.productsByCategory}); + + @override + List get props => [productsByCategory]; +} + +class ErrorProductsByCategoryState extends CategoryState { + final String message; + + ErrorProductsByCategoryState({required this.message}); + + @override + List get props => [message]; +} diff --git a/ecommerce/lib/features/products/presentation/bloc/favortites/favorites_bloc.dart b/ecommerce/lib/features/products/presentation/bloc/favortites/favorites_bloc.dart new file mode 100644 index 0000000..eeeb454 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/favortites/favorites_bloc.dart @@ -0,0 +1,60 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/core/strings/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_favorites.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_state.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_events.dart'; +import 'package:equatable/equatable.dart'; +import 'package:firebase_auth/firebase_auth.dart'; + +import 'package:flutter_bloc/flutter_bloc.dart'; + +class FavoritesBloc extends Bloc { + final GetFavoritesUsecase getAllFavorites; + FavoritesBloc({ + required this.getAllFavorites, + }) : super(FavoritesInitial()) { + on((event, emit) async { + if (event is GetAllFavoritesEvent) { + emit(LoadingFavoritesState()); + + final failureOrPosts = await getAllFavorites(userId: event.userId); + emit(_mapFailureOrPostsToState( + failureOrPosts as Either>)); + } else if (event is RefreshFavoritesEvent) { + emit(LoadingFavoritesState()); + + final failureOrPosts = await getAllFavorites(userId: event.userId); + emit(_mapFailureOrPostsToState( + failureOrPosts as Either>)); + } + }); + } + + FavoritesState _mapFailureOrPostsToState( + Either> either) { + return either.fold((failure) { + print("fffff"); + return ErrorFavoritesState(message: _mapFailureToMessage(failure)); + }, (favorites) { + print("yyyyyyy " + favorites.length.toString()); + return LoadedFavoritesState( + favorites: favorites, + ); + }); + } + + String _mapFailureToMessage(Failure failure) { + switch (failure.runtimeType) { + case ServerFailure: + return SERVER_FAILURE_MESSAGE; + case EmptyCacheFailure: + return EMPTY_CACHE_FAILURE_MESSAGE; + case OfflineFailure: + return OFFLINE_FAILURE_MESSAGE; + default: + return "Unexpected Error , Please try again later ."; + } + } +} diff --git a/ecommerce/lib/features/products/presentation/bloc/favortites/favorites_events.dart b/ecommerce/lib/features/products/presentation/bloc/favortites/favorites_events.dart new file mode 100644 index 0000000..b2784aa --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/favortites/favorites_events.dart @@ -0,0 +1,28 @@ +//part of 'favorites_bloc.dart'; + +import 'package:equatable/equatable.dart'; + +abstract class FavoritesEvent extends Equatable { + const FavoritesEvent(); + + @override + List get props => []; +} + +class GetAllFavoritesEvent extends FavoritesEvent { + final String userId; + + GetAllFavoritesEvent({required this.userId}); + + @override + List get props => [userId]; +} + +class RefreshFavoritesEvent extends FavoritesEvent { + final String userId; + + RefreshFavoritesEvent({required this.userId}); + + @override + List get props => [userId]; +} diff --git a/ecommerce/lib/features/products/presentation/bloc/favortites/favorites_state.dart b/ecommerce/lib/features/products/presentation/bloc/favortites/favorites_state.dart new file mode 100644 index 0000000..7b10571 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/favortites/favorites_state.dart @@ -0,0 +1,31 @@ +//part of 'favorites_bloc.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; + +abstract class FavoritesState { + const FavoritesState(); + + @override + List get props => []; +} + +class FavoritesInitial extends FavoritesState {} + +class LoadingFavoritesState extends FavoritesState {} + +class LoadedFavoritesState extends FavoritesState { + final List favorites; + + LoadedFavoritesState({required this.favorites}); + + @override + List get props => [favorites]; +} + +class ErrorFavoritesState extends FavoritesState { + final String message; + + ErrorFavoritesState({required this.message}); + + @override + List get props => [message]; +} diff --git a/ecommerce/lib/features/products/presentation/bloc/one_product/one_product_bloc.dart b/ecommerce/lib/features/products/presentation/bloc/one_product/one_product_bloc.dart new file mode 100644 index 0000000..2d18e58 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/one_product/one_product_bloc.dart @@ -0,0 +1,67 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/core/strings/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/usecases/check_product_is_liked.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_favorites.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_populars.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_products_by_category.dart'; +import 'package:ecommernce/features/products/domain/usecases/press_favorite_button.dart'; +import 'package:ecommernce/features/products/presentation/bloc/category/category_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/category/category_state.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_state.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/one_product/one_product_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/one_product/one_product_state.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_state.dart'; +import 'package:equatable/equatable.dart'; + +import 'package:flutter_bloc/flutter_bloc.dart'; + +class OneProductBloc extends Bloc { + final PressFavoriteButtonUsecase pressFavoriteButton; + final CheckProductIsLikedUsecase checkProductIsLikedUsecase; + OneProductBloc({ + required this.pressFavoriteButton, + required this.checkProductIsLikedUsecase, + }) : super(FavoriteButtonInitial()) { + on((event, emit) async { + if (event is CheckProductIsLikedEvent) { + final failureOrPosts = await checkProductIsLikedUsecase( + product: event.product, userId: event.userId); + emit( + _mapFailureOrPostsToState(failureOrPosts as Either)); + } else if (event is PressFavoriteButtonEvent) { + // emit(LoadingProductsByCategoryState()); + final failureOrPosts = await pressFavoriteButton( + product: event.product, isLiked: event.isLiked); + emit( + _mapFailureOrPostsToState(failureOrPosts as Either)); + } + }); + } + + OneProductState _mapFailureOrPostsToState(Either either) { + return either.fold((failure) { + print("fffff"); + return ErrorFavoriteButtonState(message: _mapFailureToMessage(failure)); + }, (isLiked) { + // print("yyyyyyy " + isLiked.toString()); + return FavoriteButtonState(isLiked: isLiked); + }); + } + + String _mapFailureToMessage(Failure failure) { + switch (failure.runtimeType) { + case ServerFailure: + return SERVER_FAILURE_MESSAGE; + case EmptyCacheFailure: + return EMPTY_CACHE_FAILURE_MESSAGE; + case OfflineFailure: + return OFFLINE_FAILURE_MESSAGE; + default: + return "Unexpected Error , Please try again later ."; + } + } +} diff --git a/ecommerce/lib/features/products/presentation/bloc/one_product/one_product_events.dart b/ecommerce/lib/features/products/presentation/bloc/one_product/one_product_events.dart new file mode 100644 index 0000000..d1aaccb --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/one_product/one_product_events.dart @@ -0,0 +1,32 @@ +//part of 'favorites_bloc.dart'; + +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:equatable/equatable.dart'; + +abstract class OneProductEvent extends Equatable { + const OneProductEvent(); + + @override + List get props => []; +} + +class PressFavoriteButtonEvent extends OneProductEvent { + final bool isLiked; + final Product product; + + PressFavoriteButtonEvent({required this.product, required this.isLiked}); + + @override + List get props => [product, isLiked]; +} + +class CheckProductIsLikedEvent extends OneProductEvent { + final Product product; + final String userId; + + CheckProductIsLikedEvent({required this.userId, required this.product}); + + @override + List get props => [product, userId]; +} +//class RefreshFavoritesEvent extends OneProduct {} diff --git a/ecommerce/lib/features/products/presentation/bloc/one_product/one_product_state.dart b/ecommerce/lib/features/products/presentation/bloc/one_product/one_product_state.dart new file mode 100644 index 0000000..fec67e6 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/one_product/one_product_state.dart @@ -0,0 +1,29 @@ +//part of 'favorites_bloc.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; + +abstract class OneProductState { + const OneProductState(); + + @override + List get props => []; +} + +class FavoriteButtonInitial extends OneProductState {} + +class FavoriteButtonState extends OneProductState { + final bool isLiked; + + FavoriteButtonState({required this.isLiked}); + + @override + List get props => [isLiked]; +} + +class ErrorFavoriteButtonState extends OneProductState { + final String message; + + ErrorFavoriteButtonState({required this.message}); + + @override + List get props => [message]; +} diff --git a/ecommerce/lib/features/products/presentation/bloc/populars/populars_bloc.dart b/ecommerce/lib/features/products/presentation/bloc/populars/populars_bloc.dart new file mode 100644 index 0000000..f66ace2 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/populars/populars_bloc.dart @@ -0,0 +1,62 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/core/strings/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_favorites.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_populars.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_state.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_state.dart'; +import 'package:equatable/equatable.dart'; + +import 'package:flutter_bloc/flutter_bloc.dart'; + +class PopularsBloc extends Bloc { + final GetPopularsUsecase getPopulars; + PopularsBloc({ + required this.getPopulars, + }) : super(PopularsInitial()) { + on((event, emit) async { + if (event is GetAllPopularsEvent) { + emit(LoadingPopularsState()); + + final failureOrPosts = await getPopulars(); + emit(_mapFailureOrPostsToState( + failureOrPosts as Either>)); + } else if (event is RefreshPopularsEvent) { + emit(LoadingPopularsState()); + + final failureOrPosts = await getPopulars(); + emit(_mapFailureOrPostsToState( + failureOrPosts as Either>)); + } + }); + } + + PopularsState _mapFailureOrPostsToState( + Either> either) { + return either.fold((failure) { + print("fffff"); + return ErrorPopularsState(message: _mapFailureToMessage(failure)); + }, (populars) { + print("yyyyyyy " + populars.length.toString()); + return LoadedPopularsState( + populars: populars, + ); + }); + } + + String _mapFailureToMessage(Failure failure) { + switch (failure.runtimeType) { + case ServerFailure: + return SERVER_FAILURE_MESSAGE; + case EmptyCacheFailure: + return EMPTY_CACHE_FAILURE_MESSAGE; + case OfflineFailure: + return OFFLINE_FAILURE_MESSAGE; + default: + return "Unexpected Error , Please try again later ."; + } + } +} diff --git a/ecommerce/lib/features/products/presentation/bloc/populars/populars_events.dart b/ecommerce/lib/features/products/presentation/bloc/populars/populars_events.dart new file mode 100644 index 0000000..21ae785 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/populars/populars_events.dart @@ -0,0 +1,14 @@ +//part of 'favorites_bloc.dart'; + +import 'package:equatable/equatable.dart'; + +abstract class PopularsEvent extends Equatable { + const PopularsEvent(); + + @override + List get props => []; +} + +class GetAllPopularsEvent extends PopularsEvent {} + +class RefreshPopularsEvent extends PopularsEvent {} diff --git a/ecommerce/lib/features/products/presentation/bloc/populars/populars_state.dart b/ecommerce/lib/features/products/presentation/bloc/populars/populars_state.dart new file mode 100644 index 0000000..b9d2248 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/populars/populars_state.dart @@ -0,0 +1,31 @@ +//part of 'favorites_bloc.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; + +abstract class PopularsState { + const PopularsState(); + + @override + List get props => []; +} + +class PopularsInitial extends PopularsState {} + +class LoadingPopularsState extends PopularsState {} + +class LoadedPopularsState extends PopularsState { + final List populars; + + LoadedPopularsState({required this.populars}); + + @override + List get props => [populars]; +} + +class ErrorPopularsState extends PopularsState { + final String message; + + ErrorPopularsState({required this.message}); + + @override + List get props => [message]; +} diff --git a/ecommerce/lib/features/products/presentation/bloc/search/search_bloc.dart b/ecommerce/lib/features/products/presentation/bloc/search/search_bloc.dart new file mode 100644 index 0000000..fa29677 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/search/search_bloc.dart @@ -0,0 +1,59 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/core/strings/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_favorites.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_populars.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_products_by_search.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_state.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_state.dart'; +import 'package:ecommernce/features/products/presentation/bloc/search/search_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/search/search_state.dart'; +import 'package:equatable/equatable.dart'; + +import 'package:flutter_bloc/flutter_bloc.dart'; + +class SearchBloc extends Bloc { + final GetProductsBySearchUsecase getProductsBySearch; + SearchBloc({ + required this.getProductsBySearch, + }) : super(SearchInitial()) { + on((event, emit) async { + if (event is GetProductsBySearchEvent) { + emit(LoadingSearchState()); + + final failureOrPosts = + await getProductsBySearch(searchText: event.searchText); + emit(_mapFailureOrPostsToState( + failureOrPosts as Either>)); + } + }); + } + + SearchState _mapFailureOrPostsToState(Either> either) { + return either.fold((failure) { + print("fffff"); + return ErrorSearchState(message: _mapFailureToMessage(failure)); + }, (productsBySearch) { + print("yyyyyyy " + productsBySearch.length.toString()); + return LoadedSearchState( + productsBySearch: productsBySearch, + ); + }); + } + + String _mapFailureToMessage(Failure failure) { + switch (failure.runtimeType) { + case ServerFailure: + return SERVER_FAILURE_MESSAGE; + case EmptyCacheFailure: + return EMPTY_CACHE_FAILURE_MESSAGE; + case OfflineFailure: + return OFFLINE_FAILURE_MESSAGE; + default: + return "Unexpected Error , Please try again later ."; + } + } +} diff --git a/ecommerce/lib/features/products/presentation/bloc/search/search_events.dart b/ecommerce/lib/features/products/presentation/bloc/search/search_events.dart new file mode 100644 index 0000000..12d1611 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/search/search_events.dart @@ -0,0 +1,21 @@ +//part of 'favorites_bloc.dart'; + +import 'package:equatable/equatable.dart'; + +abstract class SearchEvent extends Equatable { + const SearchEvent(); + + @override + List get props => []; +} + +class GetProductsBySearchEvent extends SearchEvent { + final String searchText; + + GetProductsBySearchEvent({required this.searchText}); + + @override + List get props => [searchText]; +} + +class RefreshProductsBySearchEvent extends SearchEvent {} diff --git a/ecommerce/lib/features/products/presentation/bloc/search/search_state.dart b/ecommerce/lib/features/products/presentation/bloc/search/search_state.dart new file mode 100644 index 0000000..82fc909 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/bloc/search/search_state.dart @@ -0,0 +1,31 @@ +//part of 'favorites_bloc.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; + +abstract class SearchState { + const SearchState(); + + @override + List get props => []; +} + +class SearchInitial extends SearchState {} + +class LoadingSearchState extends SearchState {} + +class LoadedSearchState extends SearchState { + final List productsBySearch; + + LoadedSearchState({required this.productsBySearch}); + + @override + List get props => [productsBySearch]; +} + +class ErrorSearchState extends SearchState { + final String message; + + ErrorSearchState({required this.message}); + + @override + List get props => [message]; +} diff --git a/ecommerce/lib/features/products/presentation/pages/category_page.dart b/ecommerce/lib/features/products/presentation/pages/category_page.dart new file mode 100644 index 0000000..61b6614 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/pages/category_page.dart @@ -0,0 +1,111 @@ +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/features/products/data/datasources/products_local_datasource.dart'; +import 'package:ecommernce/features/products/data/datasources/products_remote_datasource.dart'; +import 'package:ecommernce/features/products/data/repositories/product_repository_imp.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_products_by_category.dart'; +import 'package:ecommernce/features/products/presentation/bloc/category/category_bloc.dart'; +import 'package:ecommernce/features/products/presentation/bloc/category/category_events.dart'; +import 'package:ecommernce/features/products/presentation/widgets/category_page/products_by_category_list_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; + +class slCategory extends StatelessWidget { + String Catigory; + slCategory(this.Catigory, {Key? key}) : super(key: key); + @override + Widget build(Object context) { + return MultiBlocProvider(providers: [ + BlocProvider(create: (_) { + return CategoryBloc( + getProductsByCategory: GetProductsByCategoryUsecase( + repository: ProductsRepositoryImpl( + localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ProductsRemoteDataSourceImpl()))); + }) + ], child: sfCatigory(Catigory)); + } +} + +class sfCatigory extends StatefulWidget { + String catigoryName; + + sfCatigory(this.catigoryName, {Key? key}) : super(key: key); + @override + State createState() { + return catigoryState(); + } +} + +class catigoryState extends State { + late String catigorySearch; + @override + void initState() { + // TODO: implement initState + super.initState(); + + if (widget.catigoryName == "Jackets") { + catigorySearch = "jacket"; + } else if (widget.catigoryName == "T-Shirts") { + catigorySearch = "tshirt"; + } else if (widget.catigoryName == "Jeans") { + catigorySearch = "jeans"; + } else { + catigorySearch = "boots"; + } + //return catigoryby("boots", context); + BlocProvider.of(context) + .add(GetProductsByCategoryEvent(category: catigorySearch)); + } + + @override + Widget build(BuildContext context) { + final totalHeight = MediaQuery.of(context).size.height; + final totalWidth = MediaQuery.of(context).size.width; + CollectionReference ref1 = + FirebaseFirestore.instance.collection("products"); + return Scaffold( + body: Container( + width: MediaQuery.of(context).size.width, + color: Color(0xffd3faff), + child: Column( + children: [ + Row(children: [ + Expanded( + child: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.only( + top: totalHeight / 8 / 2.5, + bottom: totalHeight / 120, + left: totalWidth / 40), + child: IconButton( + iconSize: 30, + icon: Icon(Icons.arrow_back_rounded), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + ), + ]), + Container( + child: Text( + widget.catigoryName, + style: TextStyle(fontSize: 25, fontFamily: "New"), + ), + ), + SizedBox( + height: 20, + ), + Container( + // color: Colors.red, + height: MediaQuery.of(context).size.height - 156, + child: catigoryby(catigorySearch, context)) + ], + ), + ), + ); + } +} diff --git a/ecommerce/lib/features/products/presentation/pages/detalis_page.dart b/ecommerce/lib/features/products/presentation/pages/detalis_page.dart new file mode 100644 index 0000000..e90461c --- /dev/null +++ b/ecommerce/lib/features/products/presentation/pages/detalis_page.dart @@ -0,0 +1,211 @@ +import 'package:ecommernce/core/widgets/loading_widget.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/presentation/widgets/detalis_page/discription_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/detalis_page/colors_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/detalis_page/images_courosel_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/detalis_page/name_and_cost_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/detalis_page/rating_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/detalis_page/reviews_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/detalis_page/send_request_button_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/favorite_icon.dart'; +import 'package:ecommernce/features/products/presentation/widgets/message_display_widget.dart'; +import 'package:ecommernce/features/reviews/data/datasources/reviews_remote_datasource.dart'; +import 'package:ecommernce/features/reviews/data/repositories/review_repository_imp.dart'; +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; +import 'package:ecommernce/features/reviews/domain/usecases/get_all_reviews.dart'; +import 'package:ecommernce/features/reviews/domain/usecases/get_best_review.dart'; +import 'package:ecommernce/features/reviews/presentation/bloc/review/review_bloc.dart'; +import 'package:ecommernce/features/reviews/presentation/bloc/review/review_events.dart'; +import 'package:ecommernce/features/reviews/presentation/bloc/review/review_state.dart'; +import 'package:ecommernce/features/reviews/presentation/pages/review_page.dart'; +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/features/products/data/datasources/products_local_datasource.dart'; +import 'package:ecommernce/features/products/data/datasources/products_remote_datasource.dart'; +import 'package:ecommernce/features/products/data/repositories/product_repository_imp.dart'; +import 'package:ecommernce/features/products/domain/usecases/check_product_is_liked.dart'; +import 'package:ecommernce/features/products/domain/usecases/press_favorite_button.dart'; +import 'package:ecommernce/features/products/presentation/bloc/one_product/one_product_bloc.dart'; +import 'package:ecommernce/features/products/presentation/bloc/one_product/one_product_events.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; + +class slDetalis extends StatelessWidget { + Product pro; + String id; + slDetalis(this.pro, this.id, {Key? key}) : super(key: key); + @override + Widget build(BuildContext context) { + return MultiBlocProvider(providers: [ + BlocProvider(create: (_) { + return OneProductBloc( + pressFavoriteButton: PressFavoriteButtonUsecase( + repository: ProductsRepositoryImpl( + localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ProductsRemoteDataSourceImpl())), + checkProductIsLikedUsecase: CheckProductIsLikedUsecase( + repository: ProductsRepositoryImpl( + localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ProductsRemoteDataSourceImpl()))); + }), + BlocProvider(create: (_) { + return ReviewsBloc( + getAllReviews: GetAllReviewsUsecase( + repository: ReviewsRepositoryImpl( + // localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ReviewsRemoteDataSourceImpl())), + getBestreview: GetBestReviewUsecase( + repository: ReviewsRepositoryImpl( + // localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ReviewsRemoteDataSourceImpl()))); + }) + ], child: sfDetalis(pro, id)); + } +} + +class sfDetalis extends StatefulWidget { + Product pro; + String id; + sfDetalis(this.pro, this.id, {Key? key}) : super(key: key); + @override + State createState() { + return stateDetalis(pro, id); + } +} + +class stateDetalis extends State { + //final GFBottomSheetController sheetController = GFBottomSheetController(); + Product? pro; + String? id; + Review? besReview; + stateDetalis(this.pro, this.id); + + @override + void initState() { + // TODO: implement initState + super.initState(); + if (id != '-1') { + BlocProvider.of(context).add(CheckProductIsLikedEvent( + product: widget.pro, + userId: FirebaseAuth.instance.currentUser!.email!)); + } + BlocProvider.of(context) + .add(GetBestReviewEvent(widget.pro.id!)); + // detalisProvider + // .getRead(context) + // .getBestReview(FirebaseAuth.instance.currentUser!.email!); + } + + @override + Widget build(BuildContext context) { + final totalHeight = MediaQuery.of(context).size.height; + final totalWidth = MediaQuery.of(context).size.width; + return WillPopScope( + onWillPop: () async { + Navigator.of(context).pop(true); + return true; + }, + child: Scaffold( + appBar: AppBar(), + body: Container( + height: totalHeight, + color: Color(0xffd3faff), + child: ListView( + children: [ + imagesCarousel(pro!.images!), + nameAndCost(pro!.name!, pro!.cost!), + colors(pro!.colors!), + description(pro!.description!), + SizedBox(height: 20), + rating(double.parse(pro!.rating!)), + SizedBox(height: 20), + Container( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + Expanded( + child: Text( + 'Reviews', + style: TextStyle(fontSize: 16, fontFamily: "New"), + ), + ), + Expanded( + child: GestureDetector( + child: Text( + 'See All Reivews', + style: TextStyle(fontSize: 11, fontFamily: "New"), + textAlign: TextAlign.end, + ), + onTap: () { + BlocProvider.of(context) + .add(GetAllReviewsEvent(widget.pro.id!)); + BlocListener( + listener: (context, state) { + if (state is LoadingReviewsState) { + // LoadingWidget(); + showDialog( + context: context, + builder: (_) { + return LoadingWidget(); + }); + } else if (state is LoadedReviewsState) { + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return slReviewsPage( + reviews: state.allReviews); + })); + } + Icon(Icons.favorite_border, + color: Colors.black); + }, + child: SizedBox(), + ); + }, + ), + ), + ], + ), + ), + /* detalisProvider.getWatch(context).bestReview != null + ? reviews(context, pro!.id!, + detalisProvider.getRead(context).bestReview!) + : Container( + width: 250, + height: 75, + ),*/ + BlocBuilder( + builder: (context, state) { + if (state is LoadedBestReviewState) { + return state.bestReview.id != null + ? reviews(context, pro!.id!, state.bestReview) + : Container( + width: 250, + height: 75, + ); + } else if (state is ErrorReviewsState) { + return MessageDisplayWidget(message: state.message); + } + return LoadingWidget(); + }), + SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + sendRequest(context, pro!), + favoriteIcon(context, pro!), + ], + ), + SizedBox( + height: 20, + ) + ], + ), + ))); + } +} diff --git a/ecommerce/lib/features/products/presentation/pages/favorites_page.dart b/ecommerce/lib/features/products/presentation/pages/favorites_page.dart new file mode 100644 index 0000000..cf57bfa --- /dev/null +++ b/ecommerce/lib/features/products/presentation/pages/favorites_page.dart @@ -0,0 +1,90 @@ +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/core/widgets/loading_widget.dart'; +import 'package:ecommernce/features/products/data/datasources/products_local_datasource.dart'; +import 'package:ecommernce/features/products/data/datasources/products_remote_datasource.dart'; +import 'package:ecommernce/features/products/data/repositories/product_repository_imp.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_favorites.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_bloc.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_state.dart'; +import 'package:ecommernce/features/products/presentation/widgets/favorites_page/favorites_list_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/message_display_widget.dart'; +import 'package:ecommernce/modules/favorites/favoriteWidget.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class slFavoritePage extends StatelessWidget { + var f = SharedPreferences.getInstance(); + @override + Widget build(BuildContext context) { + return sfFavoritePage(); + } +} + +class sfFavoritePage extends StatefulWidget { + sfFavoritePage({Key? key}) : super(key: key); + @override + State createState() { + return stateFavoritePage(); + } +} + +class stateFavoritePage extends State { + @override + void initState() { + // TODO: implement initState + super.initState(); + BlocProvider.of(context).add(GetAllFavoritesEvent( + userId: FirebaseAuth.instance.currentUser!.email!)); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: Text("Favorites"), + ), + body: /*Container( + //height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + color: Color(0xffd3faff), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 40, + ), + Container( + height: MediaQuery.of(context).size.height - + AppBar().preferredSize.height - + 40 - + 34, + color: Color(0xffd3faff), + child: FirebaseAuth.instance.currentUser != null + ? favoriteListWidget(context) + : Center( + child: Text( + "You must to log in", + style: TextStyle(fontSize: 20), + ))) + ], + ), + ),*/ + BlocBuilder( + builder: (context, state) { + if (state is LoadingFavoritesState) { + return LoadingWidget(); + } else if (state is LoadedFavoritesState) { + return favoriteListWidget( + context: context, favorites: state.favorites); + } else if (state is ErrorFavoritesState) { + return MessageDisplayWidget(message: state.message); + } + return LoadingWidget(); + })); + } +} diff --git a/ecommerce/lib/features/products/presentation/pages/home_page.dart b/ecommerce/lib/features/products/presentation/pages/home_page.dart new file mode 100644 index 0000000..bfa2679 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/pages/home_page.dart @@ -0,0 +1,159 @@ +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/core/widgets/loading_widget.dart'; +import 'package:ecommernce/features/products/data/datasources/products_local_datasource.dart'; +import 'package:ecommernce/features/products/data/datasources/products_remote_datasource.dart'; +import 'package:ecommernce/features/products/data/repositories/product_repository_imp.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_populars.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_bloc.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_state.dart'; +import 'package:ecommernce/features/products/presentation/pages/search_page.dart'; +import 'package:ecommernce/features/products/presentation/widgets/home_page/category_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/home_page/most_popular_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/message_display_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; + +class slhomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MultiBlocProvider(providers: [ + BlocProvider(create: (_) { + return PopularsBloc( + getPopulars: GetPopularsUsecase( + repository: ProductsRepositoryImpl( + localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ProductsRemoteDataSourceImpl()))); + }) + ], child: sfhomepage()); + } +} + +class sfhomepage extends StatefulWidget { + sfhomepage({Key? key}) : super(key: key); + @override + State createState() { + return statehomepage(); + } +} + +class statehomepage extends State { + //late List mostPopular; + @override + void initState() { + // TODO: implement initState + super.initState(); + BlocProvider.of(context).add(GetAllPopularsEvent()); + } + + @override + Widget build(BuildContext context) { + return Container( + height: MediaQuery.of(context).size.height - 60, + color: Color(0xffd3faff), + child: Column( + children: [ + //SizedBox(height: 100,), + Container( + // color: Colors.blue, + height: 100, + padding: EdgeInsets.only(top: 50, left: 10, right: 10), + child: Text( + "Ecommernce", + style: TextStyle( + fontSize: 20, + ), + )), + GestureDetector( + child: Container( + margin: EdgeInsets.symmetric(horizontal: 10), + padding: EdgeInsets.symmetric(horizontal: 10), + // color: Colors.white, + width: 400, + child: Row( + children: [ + Container( + width: 300, + height: 50, + ), + Spacer(), + Icon(Icons.search) + ], + ), + decoration: BoxDecoration( + color: Colors.white70, + borderRadius: BorderRadius.circular(5), + ), + ), + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return slSearch(); + })); + }, + ), + SizedBox( + height: 30, + ), + Container( + child: Text( + " Catigories", + style: TextStyle(fontSize: 20, fontFamily: "New"), + ), + padding: EdgeInsets.only(right: 260), + ), + SizedBox( + height: 30, + ), + Row(children: [ + SizedBox( + width: 0, + ), //Jackets // https://5.imimg.com/data5/NM/LX/MY-42532489/mens-black-jacket-500x500.jpg + Catigory(context, "Jackets", + "https://5.imimg.com/data5/NM/LX/MY-42532489/mens-black-jacket-500x500.jpg"), + SizedBox( + width: 0, + ), + Catigory(context, "T-Shirts", + "https://img1.g-star.com/product/c_fill,f_auto,h_630,q_80/v1614686111/D14143-336-6484-M05/g-star-raw-raw-graphic-slim-t-shirt-black.jpg"), + SizedBox( + width: 0, + ), // Jeans // https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSgxTAikYMr7EqAyPmAQHS73iqcTAc4vGCNGQ&usqp=CAU + Catigory(context, "Jeans", + "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSgxTAikYMr7EqAyPmAQHS73iqcTAc4vGCNGQ&usqp=CAU"), + SizedBox( + width: 0, + ), // Boots // https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQKPx_Mkte5IqHtFMkU6pXUV_mMkBlE9hSEsg&usqp=CAU + Catigory(context, "Boots", + "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQKPx_Mkte5IqHtFMkU6pXUV_mMkBlE9hSEsg&usqp=CAU"), + ]), + SizedBox( + height: 30, + ), + Container( + child: Text( + "Most Popular", + style: TextStyle(fontSize: 18, fontFamily: "New"), + ), + padding: EdgeInsets.only(right: 225), + ), + SizedBox( + height: 30, + ), + BlocBuilder(builder: (context, state) { + if (state is LoadingPopularsState) { + return LoadingWidget(); + } else if (state is LoadedPopularsState) { + return mostPupularList( + context: context, Populars: state.populars); + } else if (state is ErrorPopularsState) { + return MessageDisplayWidget(message: state.message); + } + return LoadingWidget(); + }), + ], + ), + ); + } +} diff --git a/ecommerce/lib/features/products/presentation/pages/search_page.dart b/ecommerce/lib/features/products/presentation/pages/search_page.dart new file mode 100644 index 0000000..5df4784 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/pages/search_page.dart @@ -0,0 +1,135 @@ +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/core/widgets/loading_widget.dart'; +import 'package:ecommernce/features/products/data/datasources/products_local_datasource.dart'; +import 'package:ecommernce/features/products/data/datasources/products_remote_datasource.dart'; +import 'package:ecommernce/features/products/data/repositories/product_repository_imp.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_products_by_search.dart'; +import 'package:ecommernce/features/products/presentation/bloc/search/search_bloc.dart'; +import 'package:ecommernce/features/products/presentation/bloc/search/search_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/search/search_state.dart'; +import 'package:ecommernce/features/products/presentation/widgets/message_display_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/search_page/search_list_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; + +class slSearch extends StatelessWidget { + const slSearch({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MultiBlocProvider(providers: [ + BlocProvider(create: (_) { + return SearchBloc( + getProductsBySearch: GetProductsBySearchUsecase( + repository: ProductsRepositoryImpl( + localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ProductsRemoteDataSourceImpl()))); + }) + ], child: sfSearch()); + } +} + +class sfSearch extends StatefulWidget { + const sfSearch({Key? key}) : super(key: key); + + @override + State createState() => _stateSearch(); +} + +class _stateSearch extends State { + late TextEditingController text; + late String query; + + @override + void initState() { + // TODO: implement initState + super.initState(); + text = TextEditingController(); + query = ""; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SingleChildScrollView( + child: Container( + height: 895, + color: Color(0xffd3faff), + child: Column(children: [ + SizedBox(height: 80), + Container( + margin: EdgeInsets.symmetric(horizontal: 10), + padding: EdgeInsets.symmetric(horizontal: 10), + // color: Colors.white, + width: 400, + child: Row( + children: [ + Container( + width: 300, + child: TextField( + textCapitalization: TextCapitalization.sentences, + onChanged: (v) { + //setState(() { + //query = v; + //}); + BlocProvider.of(context) + .add(GetProductsBySearchEvent(searchText: v)); + }, + controller: text, + maxLines: 1, + autofocus: true, + //controller: email, + decoration: InputDecoration(border: InputBorder.none), + ), + ), + Spacer(), + Icon(Icons.search) + ], + ), + decoration: BoxDecoration( + color: Colors.white70, + borderRadius: BorderRadius.circular(5), + ), + ), + Container( + height: 600, + child: BlocBuilder( + builder: (context, state) { + if (state is LoadingSearchState) { + return LoadingWidget(); + } else if (state is LoadedSearchState) { + return ProuctsBySearch( + productsBySearch: state.productsBySearch); + } else if (state is ErrorSearchState) { + return MessageDisplayWidget(message: state.message); + } + return LoadingWidget(); + }), + + /*FutureBuilder( + future: + searchProvider.getRead(context).getProductsBySearch(query), + builder: (context, snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return Center( + child: CircularProgressIndicator(), + ); + default: + return ListView.builder( + itemCount: snapshot.data!.length, + itemBuilder: (context, index) { + List products = snapshot.data!; + final pro = products[index]; + return slOneProduct(pro); + }); + } + }, + ),*/ + ) + ])), + )); + } +} diff --git a/ecommerce/lib/features/products/presentation/widgets/category_page/products_by_category_list_widget.dart b/ecommerce/lib/features/products/presentation/widgets/category_page/products_by_category_list_widget.dart new file mode 100644 index 0000000..0e5a364 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/category_page/products_by_category_list_widget.dart @@ -0,0 +1,29 @@ +import 'package:ecommernce/core/widgets/loading_widget.dart'; +import 'package:ecommernce/features/products/presentation/bloc/category/category_bloc.dart'; +import 'package:ecommernce/features/products/presentation/bloc/category/category_state.dart'; +import 'package:ecommernce/features/products/presentation/widgets/message_display_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/one_product_big_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +Widget catigoryby(String s, BuildContext context) { + return BlocBuilder(builder: (context, state) { + if (state is LoadingProductsByCategoryState) { + return LoadingWidget(); + } else if (state is LoadedProductsByCategoryState) { + return productsByCategoryList(products: state.productsByCategory); + } else if (state is ErrorProductsByCategoryState) { + return MessageDisplayWidget(message: state.message); + } + return LoadingWidget(); + }); +} + +Widget productsByCategoryList({required List products}) { + return ListView.builder( + itemCount: products.length, + itemBuilder: (context, index) { + final pro = products[index]; + return slOneProduct(pro); + }); +} diff --git a/ecommerce/lib/features/products/presentation/widgets/detalis_page/color_and_quantity_list_widget.dart b/ecommerce/lib/features/products/presentation/widgets/detalis_page/color_and_quantity_list_widget.dart new file mode 100644 index 0000000..98d39e4 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/detalis_page/color_and_quantity_list_widget.dart @@ -0,0 +1,50 @@ +import 'package:ecommernce/features/products/presentation/widgets/detalis_page/one_color_widget.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/order/order_cubit.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class slcolorsAndQuantityList extends StatelessWidget { + var size; + var colors; + slcolorsAndQuantityList(this.size, this.colors, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MultiBlocProvider(providers: [ + BlocProvider(create: (_) { + return OrderCubit(); + }), + ], child: colorsAndQuantityList(size, colors)); + } +} + +class colorsAndQuantityList extends StatefulWidget { + var size; + var colors; + + colorsAndQuantityList(this.size, this.colors, {Key? key}) : super(key: key); + + @override + State createState() => colorsAndQuantityListState(); +} + +class colorsAndQuantityListState extends State { + @override + Widget build(BuildContext context) { + print("colorsAndQuantityListState state"); + return Container( + //alignment: Alignment.topLeft, + //color: Colors.amber, + height: 200, + width: 200, + child: ListView.builder( + scrollDirection: Axis.vertical, + itemCount: widget.colors!.length, + itemBuilder: (BuildContext context, int index) { + var color = int.parse('0xFF' + widget.colors![index]); + return oneColor(widget.size, widget.colors![index]); + }, + ), + ); + } +} diff --git a/ecommerce/lib/features/products/presentation/widgets/detalis_page/colors_widget.dart b/ecommerce/lib/features/products/presentation/widgets/detalis_page/colors_widget.dart new file mode 100644 index 0000000..cd6b19f --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/detalis_page/colors_widget.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; + +Widget colors(List colors) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20), + height: 50, + child: Row(children: [ + Expanded( + child: Text('Colors', + style: TextStyle(fontSize: 16, fontFamily: "New"))), + Expanded( + child: Container( + height: 20, + //width: 300, + child: ListView.builder( + reverse: true, + scrollDirection: Axis.horizontal, + itemCount: colors.length, + itemBuilder: (BuildContext context, int index) { + var color = int.parse('0xFF' + colors[index]); + return Container( + height: 40, + width: 30, + decoration: + BoxDecoration(shape: BoxShape.circle, color: Color(color)), + ); + }, + ), + ), + ) + ]), + ); +} diff --git a/ecommerce/lib/features/products/presentation/widgets/detalis_page/discription_widget.dart b/ecommerce/lib/features/products/presentation/widgets/detalis_page/discription_widget.dart new file mode 100644 index 0000000..76d65a9 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/detalis_page/discription_widget.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +Widget description(String description) { + return Container( + //height: 100, + //width: 300, + margin: const EdgeInsets.symmetric(horizontal: 20), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all( + color: Colors.blue, + width: 0.5, + ), + borderRadius: BorderRadius.circular(12), + ), + child: Container( + alignment: Alignment.topLeft, + child: Text( + description, + textAlign: TextAlign.left, + style: TextStyle(fontFamily: "New", fontSize: 13), + ), + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10), + ), + ); +} diff --git a/ecommerce/lib/features/products/presentation/widgets/detalis_page/images_courosel_widget.dart b/ecommerce/lib/features/products/presentation/widgets/detalis_page/images_courosel_widget.dart new file mode 100644 index 0000000..bc17c06 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/detalis_page/images_courosel_widget.dart @@ -0,0 +1,80 @@ +import 'package:carousel_slider/carousel_controller.dart'; +import 'package:carousel_slider/carousel_slider.dart'; +import 'package:flutter/material.dart'; + +class imagesCarousel extends StatefulWidget { + List images; + imagesCarousel(this.images, {Key? key}) : super(key: key); + + @override + State createState() { + return imagesCarouselState(); + } +} + +class imagesCarouselState extends State { + int _current = 0; + final CarouselController _controller = CarouselController(); + + @override + Widget build(BuildContext context) { + return Container( + height: 250, + width: MediaQuery.of(context).size.width, + child: Column(mainAxisSize: MainAxisSize.min, children: [ + Expanded( + child: CarouselSlider.builder( + carouselController: _controller, + itemCount: widget.images.length, + itemBuilder: + (BuildContext context, int itemIndex, int pageViewIndex) => + Container( + child: Container( + height: 200, + color: Colors.white54, + width: MediaQuery.of(context).size.width, + child: ClipRRect( + child: Image.network(widget.images[itemIndex], + fit: BoxFit.fitHeight), + )), + ), + options: CarouselOptions( + height: 200, + aspectRatio: 16 / 9, + viewportFraction: 0.8, + initialPage: 0, + enableInfiniteScroll: true, + reverse: true, + enlargeCenterPage: true, + enlargeFactor: 0.3, + scrollDirection: Axis.horizontal, + onPageChanged: (index, reason) { + setState(() { + _current = index; + }); + }), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: widget.images.asMap().entries.map((entry) { + return GestureDetector( + onTap: () => _controller.animateToPage(entry.key), + child: Container( + width: 12.0, + height: 12.0, + margin: EdgeInsets.symmetric(vertical: 4, horizontal: 4.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: (Theme.of(context).brightness == Brightness.dark + ? Colors.white + : Colors.blue) + .withOpacity(_current == entry.key ? 1 : 0.4)), + ), + ); + }).toList(), + ), + ]), + ); + } +} diff --git a/ecommerce/lib/features/products/presentation/widgets/detalis_page/name_and_cost_widget.dart b/ecommerce/lib/features/products/presentation/widgets/detalis_page/name_and_cost_widget.dart new file mode 100644 index 0000000..6a2717a --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/detalis_page/name_and_cost_widget.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +Widget nameAndCost(String name, String cost) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20), + height: 50, + child: Row( + children: [ + Expanded( + child: Text( + name, + style: TextStyle(fontSize: 16, fontFamily: "New"), + ), + ), + Expanded( + child: Text( + "\$" + cost, + style: TextStyle(fontSize: 16, fontFamily: "New"), + textAlign: TextAlign.end, + ), + ), + ], + ), + ); +} diff --git a/ecommerce/lib/features/products/presentation/widgets/detalis_page/one_color_widget.dart b/ecommerce/lib/features/products/presentation/widgets/detalis_page/one_color_widget.dart new file mode 100644 index 0000000..9b0a805 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/detalis_page/one_color_widget.dart @@ -0,0 +1,97 @@ +import 'package:ecommernce/features/purchase/presentation/bloc/order/order_cubit.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class oneColor extends StatefulWidget { + String color; + String size; + TextEditingController textController = TextEditingController(); + var quantitiy = 0; + oneColor(this.size, this.color, {Key? key}) : super(key: key); + + @override + State createState() => _oneColorState(); +} + +class _oneColorState extends State { + @override + Widget build(BuildContext context) { + print("one color state"); + //var color = int.parse('0xFF' + pro.colors![index]); + var color = int.parse('0xFF' + widget.color); + + widget.textController.text = widget.quantitiy.toString(); + return Row( + children: [ + GestureDetector( + child: Container( + height: 40, + width: 30, + decoration: BoxDecoration( + //border: + shape: BoxShape.circle, + color: Color(color)), + ), + onTap: () {}, + ), + Spacer(), + Container( + height: 30, + width: 80, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + GestureDetector( + onTap: () { + widget.quantitiy++; + var key = widget.size + '0xFF' + widget.color; + //print(key); + BlocProvider.of(context) + .editItems(key, widget.quantitiy.toString()); + setState( + () { + widget.textController.text = + widget.quantitiy.toString(); + }, + ); + //print("increase quan " + quantitiy.toString()); + }, + child: Icon( + Icons.arrow_circle_up, + size: 20, + ), + ), + Container( + alignment: Alignment.center, + height: 30, + width: 30, + child: TextField( + textAlign: TextAlign.center, + readOnly: true, + controller: widget.textController, + )), + GestureDetector( + onTap: () { + if (widget.quantitiy <= 0) { + return; + } + + widget.quantitiy--; + var key = widget.size + '0xFF' + widget.color; + BlocProvider.of(context) + .editItems(key, widget.quantitiy.toString()); + setState(() { + widget.textController.text = widget.quantitiy.toString(); + }); + }, + child: Icon( + Icons.arrow_circle_down, + size: 20, + ), + ), + ], + )) + ], + ); + } +} diff --git a/ecommerce/lib/features/products/presentation/widgets/detalis_page/rating_widget.dart b/ecommerce/lib/features/products/presentation/widgets/detalis_page/rating_widget.dart new file mode 100644 index 0000000..7dea2e9 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/detalis_page/rating_widget.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:smooth_star_rating/smooth_star_rating.dart'; + +Widget rating(double Rating) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20), + //height: 50, + child: Row( + children: [ + Expanded( + child: Text( + 'Rating', + style: TextStyle(fontSize: 16, fontFamily: "New"), + ), + ), + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SmoothStarRating( + isReadOnly: true, + rating: Rating, + size: 20, + starCount: 5, + ), + Text( + ' ' + Rating.toString(), + style: TextStyle(fontSize: 16, fontFamily: "New"), + textAlign: TextAlign.end, + ), + ], + ), + ), + ], + ), + ); +} diff --git a/ecommerce/lib/features/products/presentation/widgets/detalis_page/request_dialog_widget.dart b/ecommerce/lib/features/products/presentation/widgets/detalis_page/request_dialog_widget.dart new file mode 100644 index 0000000..6667d02 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/detalis_page/request_dialog_widget.dart @@ -0,0 +1,145 @@ +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/presentation/widgets/detalis_page/color_and_quantity_list_widget.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/order/order_cubit.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/order/order_state.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/purchase/purchase_cubit.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class slAlert extends StatelessWidget { + Product pro; + int selectedIndex; + slAlert(this.selectedIndex, this.pro, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MultiBlocProvider(providers: [ + BlocProvider(create: (_) { + return OrderCubit(); + }), + ], child: sfAlert(selectedIndex, pro)); + //sfAlert(selectedIndex,pro); + } +} + +class sfAlert extends StatefulWidget { + Product pro; + int selectedIndex; + sfAlert(this.selectedIndex, this.pro, {Key? key}) : super(key: key); + + @override + State createState() => _sfAlertState(); +} + +class _sfAlertState extends State { + @override + Widget build(BuildContext context) { + var colors = widget.pro.colors!; + List widgetss = []; + for (int i = 0; i < widget.pro.sizes!.length; i++) { + widgetss.add(colorsAndQuantityList(widget.pro.sizes![i], colors)); + } + print(widgetss.length); + return AlertDialog( + elevation: 0, + title: Text("Confirm Adding"), + content: StatefulBuilder( + builder: (context, setState) { + return Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + //color: Colors.amber, + height: 30, + width: 200, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: widget.pro.sizes!.length, + itemBuilder: (BuildContext context, int index) { + // print("asdasd" + widgetss.length.toString()); + + return GestureDetector( + child: Container( + alignment: Alignment.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: widget.selectedIndex == index + ? Border.all(color: Colors.blue, width: 2) + : null, + ), + height: 40, + width: 40, + child: Text( + widget.pro.sizes![index], + textAlign: TextAlign.center, + style: TextStyle(fontSize: 15), + ), + ), + onTap: () { + widget.selectedIndex = index; + + setState( + () {}, + ); + print(widget.selectedIndex); + // print(widgetss[selectedIndex]); + }, + ); + }, + ), + ), + SizedBox(height: 20), + Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.grey, + ), + height: 1, + width: 100, + ), + SizedBox(height: 20), + IndexedStack( + index: widget.selectedIndex, + children: widgetss, + ), + Text("asd") + ], + ); + }, + ), + actions: [ + OutlinedButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text("no")), + OutlinedButton( + onPressed: () async { + var s = BlocProvider.of(context).state as OrderState; + + Map rs = s.items; + int totalQuantity = 0; + rs.forEach((key, value) { + totalQuantity += int.parse(value); + }); + // print(totalQuantity); + Purchase p = Purchase( + p: widget.pro, + quantity: totalQuantity.toString(), + detalis: rs); + BlocProvider.of(context).addToPurchase(p); + BlocProvider.of(context) + .addToTotal(int.parse(p.p!.cost!) * int.parse(p.quantity!)); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("Done"))); + + Navigator.pop(context); + Navigator.pop(context); + }, + child: Text("yes")), + ], + ); + } +} diff --git a/ecommerce/lib/features/products/presentation/widgets/detalis_page/reviews_widget.dart b/ecommerce/lib/features/products/presentation/widgets/detalis_page/reviews_widget.dart new file mode 100644 index 0000000..13fe1c3 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/detalis_page/reviews_widget.dart @@ -0,0 +1,75 @@ +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; +import 'package:flutter/material.dart'; +import 'package:smooth_star_rating/smooth_star_rating.dart'; + +Widget reviews(BuildContext context, String id, Review bestReview) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20), + //height: 50, + child: Column( + children: [ + SizedBox(height: 7), + Container( + height: 70, + width: 250, + color: Colors.white54, + child: Column( + children: [ + Row( + children: [ + Expanded( + child: Container( + padding: EdgeInsets.only(left: 15, top: 10), + alignment: Alignment.topLeft, + child: Text( + bestReview.date!, + style: TextStyle(fontSize: 8, fontFamily: "New"), + ), + ), + ), + Expanded( + child: Container( + padding: EdgeInsets.only(right: 15, top: 10), + alignment: Alignment.topRight, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SmoothStarRating( + rating: 4.2, + size: 10, + starCount: 5, + ), + Text( + ' ${bestReview.rating}', + style: TextStyle(fontSize: 9, fontFamily: "New"), + textAlign: TextAlign.end, + ), + ], + ), + ), + ) + ], + ), + Container( + padding: EdgeInsets.only(left: 15, top: 5), + alignment: Alignment.topLeft, + child: Text( + "${bestReview.name} :", + style: TextStyle(fontSize: 11, fontFamily: "New"), + ), + ), + Container( + padding: EdgeInsets.only(left: 15, top: 5), + alignment: Alignment.topLeft, + child: Text( + bestReview.text!, + style: TextStyle(fontSize: 9, fontFamily: "New"), + ), + ), + ], + ), + ) + ], + ), + ); +} diff --git a/ecommerce/lib/features/products/presentation/widgets/detalis_page/send_request_button_widget.dart b/ecommerce/lib/features/products/presentation/widgets/detalis_page/send_request_button_widget.dart new file mode 100644 index 0000000..3be99c3 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/detalis_page/send_request_button_widget.dart @@ -0,0 +1,32 @@ +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/presentation/widgets/detalis_page/request_dialog_widget.dart'; +import 'package:flutter/material.dart'; + +Widget sendRequest(BuildContext context, Product pro) { + return Container( + height: 50, + width: 200, + margin: EdgeInsets.symmetric(horizontal: 20), + child: ElevatedButton( + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) { + var selectedIndex = 0; + return slAlert(selectedIndex, pro); + }, + ); + }, + child: Text( + "Start Request", + style: TextStyle(color: Colors.white, fontSize: 14, fontFamily: "New"), + ), + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(Colors.lightBlueAccent), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + ))), + ), + ); +} diff --git a/ecommerce/lib/features/products/presentation/widgets/favorite_icon.dart b/ecommerce/lib/features/products/presentation/widgets/favorite_icon.dart new file mode 100644 index 0000000..c662322 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/favorite_icon.dart @@ -0,0 +1,88 @@ +import 'package:ecommernce/features/auth/sign_in_page.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/presentation/bloc/one_product/one_product_bloc.dart'; +import 'package:ecommernce/features/products/presentation/bloc/one_product/one_product_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/one_product/one_product_state.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +/*Widget favoriteIcon(BuildContext context, Product pro) { + return BlocBuilder( + builder: (context, state) { + if (state is FavoriteButtonState) { + print('favoriteIcon' + state.isLiked.toString()); + if (state.isLiked) { + return IconButton( + icon: Icon(Icons.favorite, color: Colors.red), + onPressed: () { + if (FirebaseAuth.instance.currentUser == null) { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return signIn(); + })); + } + // oneProductProvider.getRead(context).buttonPressed( + // context, FirebaseAuth.instance.currentUser!.email!, pro); + }, + ); + } + return IconButton( + icon: Icon(Icons.favorite_border, color: Colors.black), + onPressed: () { + if (FirebaseAuth.instance.currentUser == null) { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return signIn(); + })); + } + // oneProductProvider.getRead(context).buttonPressed( + // context, FirebaseAuth.instance.currentUser!.email!, pro); + }, + ); + } else if (state is ErrorFavoriteButtonState) { + return MessageDisplayWidget(message: state.message); + } + return IconButton( + icon: Icon(Icons.favorite_border, color: Colors.black), + onPressed: () { + if (FirebaseAuth.instance.currentUser == null) { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return signIn(); + })); + } + // oneProductProvider.getRead(context).buttonPressed( + // context, FirebaseAuth.instance.currentUser!.email!, pro); + }, + ); + }); +} +*/ +Widget favoriteIcon(BuildContext context, Product pro) { + bool q = false; + return IconButton( + icon: + BlocBuilder(builder: (context, state) { + if (state is FavoriteButtonState) { + if (state.isLiked) { + q = true; + return Icon(Icons.favorite, color: Colors.red); + } else { + q = false; + return Icon(Icons.favorite_border, color: Colors.black); + } + } + return Icon(Icons.favorite_border, color: Colors.black); + }), + // + onPressed: () { + if (FirebaseAuth.instance.currentUser == null) { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return signIn(); + })); + } + BlocProvider.of(context) + .add(PressFavoriteButtonEvent(product: pro, isLiked: q)); + // oneProductProvider.getRead(context).buttonPressed( + // context, FirebaseAuth.instance.currentUser!.email!, pro); + }, + ); +} diff --git a/ecommerce/lib/features/products/presentation/widgets/favorites_page/favorites_list_widget.dart b/ecommerce/lib/features/products/presentation/widgets/favorites_page/favorites_list_widget.dart new file mode 100644 index 0000000..e4ba76c --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/favorites_page/favorites_list_widget.dart @@ -0,0 +1,16 @@ +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/presentation/widgets/one_product_big_widget.dart'; +import 'package:flutter/material.dart'; + +Widget favoriteListWidget({ + BuildContext? context, + List? favorites, +}) { + return ListView.builder( + physics: BouncingScrollPhysics(), + itemCount: favorites!.length, + itemBuilder: (context, index) { + final pro = favorites[index]; + return slOneProduct(pro); + }); +} diff --git a/ecommerce/lib/features/products/presentation/widgets/home_page/category_widget.dart b/ecommerce/lib/features/products/presentation/widgets/home_page/category_widget.dart new file mode 100644 index 0000000..8836ce2 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/home_page/category_widget.dart @@ -0,0 +1,40 @@ +import 'package:ecommernce/features/products/presentation/pages/category_page.dart'; +import 'package:flutter/material.dart'; + +Widget Catigory(BuildContext context, String a, String b) { + return Container( + width: MediaQuery.of(context).size.width / 4, + child: GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return slCategory(a); + })); + }, + child: Card( + child: Column( + children: [ + Container( + width: 95, + height: 120, + child: ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8.0), + topRight: Radius.circular(8.0), + ), + child: Image.network(b, + width: 95, height: 120, fit: BoxFit.fill), + )), + Container( + padding: EdgeInsets.symmetric(vertical: 5), + child: Text(a, + style: TextStyle( + color: Colors.white, fontFamily: "New", fontSize: 13)), + ) + ], + ), + color: Colors.blueAccent, + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + ), + )); +} diff --git a/ecommerce/lib/features/products/presentation/widgets/home_page/most_popular_widget.dart b/ecommerce/lib/features/products/presentation/widgets/home_page/most_popular_widget.dart new file mode 100644 index 0000000..b446b90 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/home_page/most_popular_widget.dart @@ -0,0 +1,43 @@ +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/presentation/widgets/home_page/one_product_small_widget.dart'; +import 'package:flutter/material.dart'; + +/*Widget mostPupularList(BuildContext context) { + return Container( + height: 150, + child: FutureBuilder( + future: homeProvider.getRead(context).getPopular(), + builder: (context, snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return Center( + child: CircularProgressIndicator(), + ); + default: + List mostPopular = homeProvider.getRead(context).mostPopular; + + return ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: mostPopular.length, + itemBuilder: (BuildContext context, int index) { + Product pro = mostPopular[index]; + return slOneProductWidgetHomePage(pro); + }, + ); + } + }, + )); +} +*/ +Widget mostPupularList({required context, required List Populars}) { + return Container( + height: 150, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: Populars.length, + itemBuilder: (BuildContext context, int index) { + Product pro = Populars[index]; + return slOneProductWidgetHomePage(pro); + }, + )); +} diff --git a/ecommerce/lib/features/products/presentation/widgets/home_page/one_product_small_widget.dart b/ecommerce/lib/features/products/presentation/widgets/home_page/one_product_small_widget.dart new file mode 100644 index 0000000..65cea30 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/home_page/one_product_small_widget.dart @@ -0,0 +1,144 @@ +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/features/products/data/datasources/products_local_datasource.dart'; +import 'package:ecommernce/features/products/data/datasources/products_remote_datasource.dart'; +import 'package:ecommernce/features/products/data/repositories/product_repository_imp.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/usecases/check_product_is_liked.dart'; +import 'package:ecommernce/features/products/domain/usecases/press_favorite_button.dart'; +import 'package:ecommernce/features/products/presentation/bloc/one_product/one_product_bloc.dart'; +import 'package:ecommernce/features/products/presentation/bloc/one_product/one_product_events.dart'; +import 'package:ecommernce/features/products/presentation/pages/detalis_page.dart'; +import 'package:ecommernce/features/products/presentation/widgets/favorite_icon.dart'; + +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; + +class slOneProductWidgetHomePage extends StatelessWidget { + Product? pro; + slOneProductWidgetHomePage(this.pro, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MultiBlocProvider(providers: [ + BlocProvider(create: (_) { + return OneProductBloc( + pressFavoriteButton: PressFavoriteButtonUsecase( + repository: ProductsRepositoryImpl( + localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ProductsRemoteDataSourceImpl())), + checkProductIsLikedUsecase: CheckProductIsLikedUsecase( + repository: ProductsRepositoryImpl( + localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ProductsRemoteDataSourceImpl()))); + }) + ], child: sfOneProductWidgetHomePage(pro)); + } +} + +class sfOneProductWidgetHomePage extends StatefulWidget { + Product? pro; + sfOneProductWidgetHomePage(this.pro, {Key? key}) : super(key: key); + + @override + State createState() => + stateOneProductWidgetHomePage(); +} + +class stateOneProductWidgetHomePage extends State { + void initState() { + if (FirebaseAuth.instance.currentUser != null) { + BlocProvider.of(context).add(CheckProductIsLikedEvent( + product: widget.pro!, + userId: FirebaseAuth.instance.currentUser!.email!)); + } + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return slDetalis( + widget.pro!, + FirebaseAuth.instance.currentUser == null + ? '-1' + : FirebaseAuth.instance.currentUser!.email!); + })).then((value) { + if (FirebaseAuth.instance.currentUser != null) { + BlocProvider.of(context).add( + CheckProductIsLikedEvent( + product: widget.pro!, + userId: FirebaseAuth.instance.currentUser!.email!)); + } + }); + }, + child: Container( + margin: EdgeInsets.symmetric(horizontal: 10), + width: 120, + child: ClipRRect( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + child: Container( + child: Column( + children: [ + Container( + height: 100, + width: 120, + child: ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8.0), + topRight: Radius.circular(8.0), + ), + child: Image.network(widget.pro!.images![0], + fit: BoxFit.fill), + )), + Container( + padding: EdgeInsets.only(left: 10), + color: Colors.white, + height: 50, + child: Row( + children: [ + Column( + children: [ + Container( + width: 60, + child: Center( + child: Text( + widget.pro!.name!, + style: TextStyle( + color: Colors.black, + fontFamily: "New", + fontSize: 11), + textAlign: TextAlign.center, + ))), + SizedBox(height: 5), + Container( + width: 30, + child: Text( + widget.pro!.cost! + "\$", + style: TextStyle( + fontSize: 12, fontFamily: "New"), + )), + // SizedBox(width: 6), + ], + ), + Spacer(), + Container( + child: favoriteIcon(context, widget.pro!), + // alignment: Alignment.topRight, + ), + ], + ), + ), + ], + ), + ), + )), + ); + } +} diff --git a/ecommerce/lib/features/products/presentation/widgets/message_display_widget.dart b/ecommerce/lib/features/products/presentation/widgets/message_display_widget.dart new file mode 100644 index 0000000..43aa5e1 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/message_display_widget.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +class MessageDisplayWidget extends StatelessWidget { + final String message; + const MessageDisplayWidget({ + Key? key, + required this.message, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: MediaQuery.of(context).size.height / 3, + child: Center( + child: SingleChildScrollView( + child: Text( + message, + style: TextStyle(fontSize: 25), + textAlign: TextAlign.center, + ), + )), + ); + } +} diff --git a/ecommerce/lib/features/products/presentation/widgets/one_product_big_widget.dart b/ecommerce/lib/features/products/presentation/widgets/one_product_big_widget.dart new file mode 100644 index 0000000..ab592d5 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/one_product_big_widget.dart @@ -0,0 +1,135 @@ +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/features/products/data/datasources/products_local_datasource.dart'; +import 'package:ecommernce/features/products/data/datasources/products_remote_datasource.dart'; +import 'package:ecommernce/features/products/data/repositories/product_repository_imp.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/usecases/check_product_is_liked.dart'; +import 'package:ecommernce/features/products/domain/usecases/press_favorite_button.dart'; +import 'package:ecommernce/features/products/presentation/bloc/one_product/one_product_bloc.dart'; +import 'package:ecommernce/features/products/presentation/bloc/one_product/one_product_events.dart'; +import 'package:ecommernce/features/products/presentation/pages/detalis_page.dart'; +import 'package:ecommernce/features/products/presentation/widgets/favorite_icon.dart'; + +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; + +class slOneProduct extends StatelessWidget { + Product? pro; + slOneProduct(this.pro, {Key? key}) : super(key: key); + @override + Widget build(BuildContext context) { + return MultiBlocProvider(providers: [ + BlocProvider(create: (_) { + return OneProductBloc( + pressFavoriteButton: PressFavoriteButtonUsecase( + repository: ProductsRepositoryImpl( + localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ProductsRemoteDataSourceImpl())), + checkProductIsLikedUsecase: CheckProductIsLikedUsecase( + repository: ProductsRepositoryImpl( + localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ProductsRemoteDataSourceImpl()))); + }) + ], child: sfOneProduct(pro)); + } +} + +class sfOneProduct extends StatefulWidget { + Product? pro; + sfOneProduct(this.pro, {Key? key}) : super(key: key); + + @override + State createState() => stateOneProduct(); +} + +class stateOneProduct extends State { + void initState() { + if (FirebaseAuth.instance.currentUser != null) { + BlocProvider.of(context).add(CheckProductIsLikedEvent( + product: widget.pro!, + userId: FirebaseAuth.instance.currentUser!.email!)); + } + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + child: Container( + height: 150, + margin: EdgeInsets.symmetric(horizontal: 60), + child: Container( + margin: EdgeInsets.symmetric(vertical: 5), + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10)), + child: Container( + child: Row( + children: [ + Container( + width: 120, + height: 120, + child: ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8.0), + bottomLeft: Radius.circular(8.0), + ), + child: Image.network(widget.pro!.images![0], + fit: BoxFit.fitHeight), + )), + //Spacer(), + Container( + width: 120, + child: Column( + children: [ + Container( + alignment: Alignment.centerRight, + height: 50, + child: Container( + child: favoriteIcon(context, widget.pro!)), + ), + Container( + height: 20, + child: Center( + child: Text( + widget.pro!.name!, + style: TextStyle(fontSize: 16, fontFamily: "New"), + )), + ), + Container( + height: 50, + child: Center( + child: Text("\$" + widget.pro!.cost!, + style: TextStyle( + fontSize: 22, fontFamily: "New"))), + ), + ], + ), + ), + ], + ), + ), + ), + )), + onTap: () { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return slDetalis( + widget.pro!, + FirebaseAuth.instance.currentUser == null + ? '-1' + : FirebaseAuth.instance.currentUser!.email!); + })).then((value) { + if (FirebaseAuth.instance.currentUser != null) { + BlocProvider.of(context).add( + CheckProductIsLikedEvent( + product: widget.pro!, + userId: FirebaseAuth.instance.currentUser!.email!)); + } + }); + }, + ); + } +} diff --git a/ecommerce/lib/features/products/presentation/widgets/search_page/search_list_widget.dart b/ecommerce/lib/features/products/presentation/widgets/search_page/search_list_widget.dart new file mode 100644 index 0000000..6087735 --- /dev/null +++ b/ecommerce/lib/features/products/presentation/widgets/search_page/search_list_widget.dart @@ -0,0 +1,12 @@ +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/presentation/widgets/one_product_big_widget.dart'; +import 'package:flutter/material.dart'; + +Widget ProuctsBySearch({required List productsBySearch}) { + return ListView.builder( + itemCount: productsBySearch.length, + itemBuilder: (context, index) { + final pro = productsBySearch[index]; + return slOneProduct(pro); + }); +} diff --git a/ecommerce/lib/features/purchase/data/datasourcses/purchase_remote_datasource.dart b/ecommerce/lib/features/purchase/data/datasourcses/purchase_remote_datasource.dart new file mode 100644 index 0000000..4d1527f --- /dev/null +++ b/ecommerce/lib/features/purchase/data/datasourcses/purchase_remote_datasource.dart @@ -0,0 +1,48 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/purchase/data/models/purchase_model.dart'; +import 'package:http/http.dart' as http; +import 'dart:async'; +import 'package:http_auth/http_auth.dart'; + +abstract class PurchaseRemoteDataSource { + Future> getSales({required String userId}); +} + +class PurchaseRemoteDataSourceImpl implements PurchaseRemoteDataSource { + PurchaseRemoteDataSourceImpl(); + + @override + Future> getSales({required String userId}) async { + List sales = []; + CollectionReference ref = FirebaseFirestore.instance.collection("products"); + QuerySnapshot ref2 = await FirebaseFirestore.instance + .collection("users") + .doc(userId) + .collection("sales") + .get(); + + for (var elementt in ref2.docs) { + String id = elementt["id"]; + String time = elementt["daytime"]; + String date = elementt["daydate"]; + List images = elementt["images"]; + String name = elementt["name"]; + String cost = elementt["cost"]; + + String quantity = elementt["quantity"]; + Product p = Product( + cost: cost, + id: id, + daydate: date, + daytime: time, + images: images, + name: name, + ); + PurchaseModel pur = PurchaseModel(p: p, quantity: quantity); + sales.add(pur); + } + + return sales; + } +} diff --git a/ecommerce/lib/features/purchase/data/models/purchase_model.dart b/ecommerce/lib/features/purchase/data/models/purchase_model.dart new file mode 100644 index 0000000..97e4c50 --- /dev/null +++ b/ecommerce/lib/features/purchase/data/models/purchase_model.dart @@ -0,0 +1,26 @@ +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; + +class PurchaseModel extends Purchase { + Product? p; + String? quantity; + Map? detalis; + + PurchaseModel({this.detalis, this.p, this.quantity}); + + factory PurchaseModel.fromJson(Map json) { + return PurchaseModel( + p: json['p'], + quantity: json['quantity'], + detalis: json['detalis'], + ); + } + + Map toJson() { + return { + 'p': p, + 'quantity': quantity, + 'detalis': detalis, + }; + } +} diff --git a/ecommerce/lib/features/purchase/data/repositories/purchase_repository_impl.dart b/ecommerce/lib/features/purchase/data/repositories/purchase_repository_impl.dart new file mode 100644 index 0000000..a1f3b06 --- /dev/null +++ b/ecommerce/lib/features/purchase/data/repositories/purchase_repository_impl.dart @@ -0,0 +1,35 @@ +import 'package:ecommernce/core/errors/exceptions.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/features/purchase/data/datasourcses/purchase_remote_datasource.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/features/purchase/domain/repositories/purchase_repository.dart'; + +class PurchaseRepositoryImpl implements PurchaseRepository { + final PurchaseRemoteDataSourceImpl remoteDataSource; + //final ProductsLocalDataSource localDataSource; + final NetworkInfo networkInfo; + PurchaseRepositoryImpl({ + required this.remoteDataSource, + //required this.localDataSource, + required this.networkInfo, + }); + + @override + Future>> getSales( + {required String userId}) async { + if (await networkInfo.isConnected) { + try { + final remoteSales = await remoteDataSource.getSales(userId: userId); + //print('getFavorites remote' + remoteFavorites.length.toString()); + // localDataSource.cacheFavorites(remotePosts); + return Right(remoteSales); + } on ServerException { + return Left(ServerFailure()); + } + } else { + return Right([]); + } + } +} diff --git a/ecommerce/lib/features/purchase/domain/entites/purchase.dart b/ecommerce/lib/features/purchase/domain/entites/purchase.dart new file mode 100644 index 0000000..252c76c --- /dev/null +++ b/ecommerce/lib/features/purchase/domain/entites/purchase.dart @@ -0,0 +1,9 @@ +import 'package:ecommernce/features/products/domain/entities/product.dart'; + +class Purchase { + Product? p; + String? quantity; + Map? detalis; + + Purchase({this.detalis, this.p, this.quantity}); +} diff --git a/ecommerce/lib/features/purchase/domain/repositories/purchase_repository.dart b/ecommerce/lib/features/purchase/domain/repositories/purchase_repository.dart new file mode 100644 index 0000000..fd07f32 --- /dev/null +++ b/ecommerce/lib/features/purchase/domain/repositories/purchase_repository.dart @@ -0,0 +1,8 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; + +abstract class PurchaseRepository { + Future>> getSales({required String userId}); +} diff --git a/ecommerce/lib/features/purchase/domain/usecases/get_sales.dart b/ecommerce/lib/features/purchase/domain/usecases/get_sales.dart new file mode 100644 index 0000000..ddb5718 --- /dev/null +++ b/ecommerce/lib/features/purchase/domain/usecases/get_sales.dart @@ -0,0 +1,17 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/repositories/product_repository.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/features/purchase/domain/repositories/purchase_repository.dart'; + +class GetSalesUsecase { + final PurchaseRepository repository; + + GetSalesUsecase({required this.repository}); + + Future>> call({required String userId}) async { + print('GetFavoritesUsecase'); + return await repository.getSales(userId: userId); + } +} diff --git a/ecommerce/lib/features/purchase/presentation/bloc/order/order_cubit.dart b/ecommerce/lib/features/purchase/presentation/bloc/order/order_cubit.dart new file mode 100644 index 0000000..7ce90b9 --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/bloc/order/order_cubit.dart @@ -0,0 +1,15 @@ +import 'package:ecommernce/features/purchase/presentation/bloc/order/order_state.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class OrderCubit extends Cubit { + OrderCubit() : super(OrderState(items: Map())); + + void editItems(String key, String value) { + if (value == '0') { + state.items.remove(key); + return; + } + state.items[key] = value; + print(state.items); + } +} diff --git a/ecommerce/lib/features/purchase/presentation/bloc/order/order_state.dart b/ecommerce/lib/features/purchase/presentation/bloc/order/order_state.dart new file mode 100644 index 0000000..88ab37b --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/bloc/order/order_state.dart @@ -0,0 +1,38 @@ +//part of 'favorites_bloc.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:flutter/material.dart'; + +class OrderState { + Map items = Map(); + OrderState({required this.items}); + + @override + List get props => []; +} + +/*class OrderssInitial extends OrderState { + Map items = Map(); + + OrderssInitial({required this.items}); +} + +class LoadedPurchasesState extends PurchaseState { + List purchases; + int total; + + LoadedPurchasesState({required this.purchases, required this.total}); + + @override + List get props => [purchases]; +} + +class ErrorProductsByCategoryState extends PurchaseState { + final String message; + + ErrorProductsByCategoryState({required this.message}); + + @override + List get props => [message]; +} +*/ \ No newline at end of file diff --git a/ecommerce/lib/features/purchase/presentation/bloc/purchase/purchase_cubit.dart b/ecommerce/lib/features/purchase/presentation/bloc/purchase/purchase_cubit.dart new file mode 100644 index 0000000..acb9693 --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/bloc/purchase/purchase_cubit.dart @@ -0,0 +1,77 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/core/strings/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_products_by_category.dart'; +import 'package:ecommernce/features/products/presentation/bloc/category/category_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/category/category_state.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/purchase/purchase_state.dart'; +import 'package:ecommernce/features/purchase/presentation/pages/check_out_page.dart'; +import 'package:ecommernce/features/purchase/presentation/widgets/check_out_page/one_item_quantity_widget.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class PurchaseCubit extends Cubit { + PurchaseCubit() : super(PurchaseState(purchases: [], total: 0)); + + void addToPurchase(Purchase p) { + //final currentState = state as LoadedPurchasesState; + var list = state.purchases; + list.add(p); + emit(PurchaseState(purchases: list, total: state.total)); + } + + void removeFromPurchase(Purchase p) { +// final currentState = state as LoadedPurchasesState; + var list = state.purchases; + list.remove(p); + emit(PurchaseState(purchases: list, total: state.total)); + } + + void addToTotal(int a) { + //final currentState = state as PurchaseState; + var total = state.total; + total += a; + emit(PurchaseState(purchases: state.purchases, total: total)); + } + + void minusFromTotal(int a) { + //final currentState = state as LoadedPurchasesState; + var total = state.total; + total -= a; + emit(PurchaseState(purchases: state.purchases, total: total)); + } + + void editQuantity(Purchase p, List wed) { + //final currentState = state as LoadedPurchasesState; + int n = 0; + for (oneItemQuantity w in wed) { + print(w.keyMap + " dddd" + w.isDeleted.toString()); + + if (!w.isDeleted) { + p.detalis![w.keyMap] = w.quantity; + n += int.parse(w.quantity); + } else { + p.detalis!.remove(w.keyMap); + } + } + + if (n > int.parse(p.quantity!)) { + state.total += (n - int.parse(p.quantity!)) * int.parse(p.p!.cost!); + } else if (n < int.parse(p.quantity!)) { + state.total -= (int.parse(p.quantity!) - n) * int.parse(p.p!.cost!); + } + if (p.detalis!.isEmpty) { + removeFromPurchase(p); + //return; + } else { + p.quantity = n.toString(); + } + + emit(PurchaseState(purchases: state.purchases, total: state.total)); + } + + void clearPurchase() { + emit(PurchaseState(purchases: [], total: 0)); + } +} diff --git a/ecommerce/lib/features/purchase/presentation/bloc/purchase/purchase_state.dart b/ecommerce/lib/features/purchase/presentation/bloc/purchase/purchase_state.dart new file mode 100644 index 0000000..5c1fb36 --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/bloc/purchase/purchase_state.dart @@ -0,0 +1,42 @@ +//part of 'favorites_bloc.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:flutter/material.dart'; + +class PurchaseState { + List purchases; + int total; + PurchaseState({required this.purchases, required this.total}); + + @override + List get props => []; +} + +/*class PurchasesInitial extends PurchaseState { + List purchases; + int total; + + PurchasesInitial({required this.purchases, required this.total}); +} + +//class LoadingPurchasesState extends PurchaseState {} + +class LoadedPurchasesState extends PurchaseState { + List purchases; + int total; + + LoadedPurchasesState({required this.purchases, required this.total}); + + @override + List get props => [purchases]; +} + +class ErrorProductsByCategoryState extends PurchaseState { + final String message; + + ErrorProductsByCategoryState({required this.message}); + + @override + List get props => [message]; +} +*/ \ No newline at end of file diff --git a/ecommerce/lib/features/purchase/presentation/bloc/sales/sales_bloc.dart b/ecommerce/lib/features/purchase/presentation/bloc/sales/sales_bloc.dart new file mode 100644 index 0000000..8039f1b --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/bloc/sales/sales_bloc.dart @@ -0,0 +1,57 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/core/strings/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_favorites.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_state.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_events.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/features/purchase/domain/usecases/get_sales.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/sales/sales_events.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/sales/sales_state.dart'; +import 'package:equatable/equatable.dart'; +import 'package:firebase_auth/firebase_auth.dart'; + +import 'package:flutter_bloc/flutter_bloc.dart'; + +class SalesBloc extends Bloc { + final GetSalesUsecase getSales; + SalesBloc({ + required this.getSales, + }) : super(SalesInitial()) { + on((event, emit) async { + if (event is GetSalesEvent) { + emit(LoadingSalesState()); + + final failureOrPosts = await getSales(userId: event.userId); + emit(_mapFailureOrSalesToState( + failureOrPosts as Either>)); + } + }); + } + + SalesState _mapFailureOrSalesToState(Either> either) { + return either.fold((failure) { + print("fffff"); + return ErrorSalesState(message: _mapFailureToMessage(failure)); + }, (sales) { + print("yyyyyyy " + sales.length.toString()); + return LoadedSalesState( + sales: sales, + ); + }); + } + + String _mapFailureToMessage(Failure failure) { + switch (failure.runtimeType) { + case ServerFailure: + return SERVER_FAILURE_MESSAGE; + case EmptyCacheFailure: + return EMPTY_CACHE_FAILURE_MESSAGE; + case OfflineFailure: + return OFFLINE_FAILURE_MESSAGE; + default: + return "Unexpected Error , Please try again later ."; + } + } +} diff --git a/ecommerce/lib/features/purchase/presentation/bloc/sales/sales_events.dart b/ecommerce/lib/features/purchase/presentation/bloc/sales/sales_events.dart new file mode 100644 index 0000000..4fe104b --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/bloc/sales/sales_events.dart @@ -0,0 +1,19 @@ +//part of 'favorites_bloc.dart'; + +import 'package:equatable/equatable.dart'; + +abstract class SalesEvent extends Equatable { + const SalesEvent(); + + @override + List get props => []; +} + +class GetSalesEvent extends SalesEvent { + final String userId; + + GetSalesEvent({required this.userId}); + + @override + List get props => [userId]; +} diff --git a/ecommerce/lib/features/purchase/presentation/bloc/sales/sales_state.dart b/ecommerce/lib/features/purchase/presentation/bloc/sales/sales_state.dart new file mode 100644 index 0000000..efc3cae --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/bloc/sales/sales_state.dart @@ -0,0 +1,32 @@ +//part of 'favorites_bloc.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; + +abstract class SalesState { + const SalesState(); + + @override + List get props => []; +} + +class SalesInitial extends SalesState {} + +class LoadingSalesState extends SalesState {} + +class LoadedSalesState extends SalesState { + final List sales; + + LoadedSalesState({required this.sales}); + + @override + List get props => [sales]; +} + +class ErrorSalesState extends SalesState { + final String message; + + ErrorSalesState({required this.message}); + + @override + List get props => [message]; +} diff --git a/ecommerce/lib/features/purchase/presentation/pages/check_out_page.dart b/ecommerce/lib/features/purchase/presentation/pages/check_out_page.dart new file mode 100644 index 0000000..c993478 --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/pages/check_out_page.dart @@ -0,0 +1,125 @@ +import 'package:ecommernce/core/firebase_services.dart'; +import 'package:ecommernce/features/map/location_page.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/purchase/purchase_cubit.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/purchase/purchase_state.dart'; +import 'package:ecommernce/features/purchase/presentation/pages/paypal_payment.dart'; +import 'package:ecommernce/features/purchase/presentation/widgets/check_out_page/expandable_tile_widget.dart'; +import 'package:ecommernce/features/purchase/presentation/widgets/check_out_page/pay_with_paypal_button.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class CheckOutPage extends StatefulWidget { + @override + _CheckOutPageState createState() => _CheckOutPageState(); +} + +class _CheckOutPageState extends State { + final GlobalKey _scaffoldKey = new GlobalKey(); + List items = []; + late List pur; + String quan = ""; + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + key: _scaffoldKey, + appBar: _appBar(), + body: _body()); + } + + AppBar _appBar() { + return AppBar( + centerTitle: true, + //backgroundColor: Colors.white, + title: Text( + 'Paypal Payment', + style: TextStyle( + fontSize: 18.0, + // color: Colors.black, + fontWeight: FontWeight.bold, + ), + ), + ); + } + + Widget _body() { + return Container( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + BlocBuilder( + builder: (context, state) { + /*if (state is LoadedPurchasesState) { + } + return SizedBox(); + */ + return Text( + "Total : \$" + state.total.toString(), + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), + ); + }), + SizedBox(height: 30), + Text( + "Items in your Cart", + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), + ), + Container( + height: MediaQuery.of(context).size.height - 500, + child: BlocBuilder( + builder: (context, state) { + /*if (state is LoadedPurchasesState) { + return + } else if (state is PurchasesInitial) { + return ListView.builder( + physics: BouncingScrollPhysics(), + itemCount: state.purchases.length, + itemBuilder: (context, index) { + pur = state.purchases; + + return _buildExpandableTile(pur[index]); + }); + } + return SizedBox(); + */ + return ListView.builder( + physics: BouncingScrollPhysics(), + itemCount: state.purchases.length, + itemBuilder: (context, index) { + pur = state.purchases; + + return BuildExpandableTile( + purchase: pur[index], context: context, quan: quan); + }); + })), + Text("Your region"), + ElevatedButton( + onPressed: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (BuildContext context) => SimpleMap())); + }, + child: Text("select your region")), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('lat'), + Container(width: 100, child: TextField()), + Text('lang'), + Container(width: 100, child: TextField()), + ], + ), + SizedBox(height: 20), + PayWithPaypalButton(context: context, items: items, pur: pur) + ], + )); + } +} diff --git a/ecommerce/lib/features/purchase/presentation/pages/paypal_payment.dart b/ecommerce/lib/features/purchase/presentation/pages/paypal_payment.dart new file mode 100644 index 0000000..b8bc513 --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/pages/paypal_payment.dart @@ -0,0 +1,237 @@ +import 'dart:core'; +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/core/api_services.dart'; +import 'package:flutter/material.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +class Payment extends StatefulWidget { + final Function onFinish; + final List items; + + Payment({required this.onFinish, required this.items}); + + @override + State createState() { + return PaymentState(); + } +} + +class PaymentState extends State { + GlobalKey _scaffoldKey = GlobalKey(); + String? checkoutUrl; + String? executeUrl; + String? accessToken; + Services services = Services(); + + // you can change default currency according to your need + Map defaultCurrency = { + "symbol": "USD ", + "decimalDigits": 2, + "symbolBeforeTheNumber": true, + "currency": "USD" + }; + + bool isEnableShipping = false; + bool isEnableAddress = false; + + String returnURL = 'return.example.com'; + String cancelURL = 'cancel.example.com'; + + //String itemName = 'iPhone 7'; + //String itemPrice = '200'; + //int quantity = 1; + + Map getOrderParams() { + /*List items = [ + { + "name": itemName, + "quantity": quantity, + "price": itemPrice, + "currency": defaultCurrency["currency"] + } + ];*/ + + List items = widget.items; + + int t = 0; + for (var n in items) { + int no = int.parse(n['quantity']); + t += int.parse(n['price']) * no; + n['currency'] = defaultCurrency["currency"]; + } + String totalAmount = t.toString(); + //String subTotalAmount = t.toString(); + + /*List items = [ + { + "name": 'iphone', + "quantity": '1', + "price": '200', + "currency": defaultCurrency["currency"] + } + ]; + String totalAmount = '200'; + String subTotalAmount = '200';*/ + + String shippingCost = '0'; + int shippingDiscountCost = 0; + String userFirstName = 'Arsalan'; + String userLastName = 'Umar'; + String addressCity = 'Islamabad'; + String addressStreet = "i-10"; + String addressZipCode = '44000'; + String addressCountry = 'Pakistan'; + String addressState = 'Islamabad'; + String addressPhoneNumber = '+923200811288'; + + Map temp = { + "intent": "sale", + "payer": {"payment_method": "paypal"}, + "transactions": [ + { + "amount": { + "total": totalAmount, + "currency": defaultCurrency["currency"], + "details": { + //"subtotal": subTotalAmount, + "shipping": shippingCost, + "shipping_discount": ((-1.0) * shippingDiscountCost).toString() + } + }, + "description": "The payment transaction description.", + "payment_options": { + "allowed_payment_method": "INSTANT_FUNDING_SOURCE" + }, + "item_list": { + "items": items, + if (isEnableShipping && isEnableAddress) + "shipping_address": { + "recipient_name": userFirstName + " " + userLastName, + "line1": addressStreet, + "line2": "", + "city": addressCity, + "country_code": addressCountry, + "postal_code": addressZipCode, + "phone": addressPhoneNumber, + "state": addressState + }, + } + } + ], + "note_to_payer": "Contact us for any questions on your order.", + "redirect_urls": {"return_url": returnURL, "cancel_url": cancelURL} + }; + return temp; + } + + var controller; + + @override + void initState() { + super.initState(); + + Future.delayed(Duration.zero, () async { + try { + accessToken = await services.getAccessToken(); + + final transactions = getOrderParams(); + final res = + await services.createPaypalPayment(transactions, accessToken); + if (res != null) { + setState(() { + checkoutUrl = res["approvalUrl"]; + executeUrl = res["executeUrl"]; + }); + } + } catch (e) { + print('exception: ' + e.toString()); + final snackBar = SnackBar( + content: Text(e.toString()), + duration: Duration(seconds: 10), + action: SnackBarAction( + label: 'Close', + onPressed: () { + // Some code to undo the change. + }, + ), + ); + //_scaffoldKey.currentState!.showSnackBar(snackBar); + } + }).then((value) { + controller = WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setBackgroundColor(const Color(0x00000000)) + ..setNavigationDelegate( + NavigationDelegate( + onProgress: (int progress) { + // Update loading bar. + }, + onPageStarted: (String url) {}, + onPageFinished: (String url) {}, + onWebResourceError: (WebResourceError error) {}, + onNavigationRequest: (NavigationRequest request) { + if (request.url.contains(returnURL)) { + print("request url ::" + request.url); + final uri = Uri.parse(request.url); + final payerID = uri.queryParameters['PayerID']; + if (payerID != null) { + services + .executePayment(executeUrl, payerID, accessToken!) + .then((id) { + widget.onFinish(id); + Navigator.of(context).pop(); + }); + } else { + Navigator.of(context).pop(); + } + //Navigator.of(context).pop(); + } + if (request.url.contains(cancelURL)) { + Navigator.of(context).pop(); + } + return NavigationDecision.navigate; + }, + ), + ) + ..loadRequest(Uri.parse(checkoutUrl!)); + print(checkoutUrl!); + }); + } + + // item name, price and quantity + + @override + Widget build(BuildContext context) { + print(checkoutUrl); + + if (checkoutUrl != null) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).backgroundColor, + leading: GestureDetector( + child: Icon(Icons.arrow_back_ios), + onTap: () => Navigator.pop(context), + ), + ), + body: WebViewWidget( + controller: controller, + ), + ); + } else { + return Scaffold( + key: _scaffoldKey, + appBar: AppBar( + leading: IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + Navigator.of(context).pop(); + }), + backgroundColor: Colors.black12, + elevation: 0.0, + ), + body: Center(child: Container(child: CircularProgressIndicator())), + ); + } + } +} diff --git a/ecommerce/lib/features/purchase/presentation/pages/sales_page.dart b/ecommerce/lib/features/purchase/presentation/pages/sales_page.dart new file mode 100644 index 0000000..cde5157 --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/pages/sales_page.dart @@ -0,0 +1,97 @@ +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/core/widgets/loading_widget.dart'; +import 'package:ecommernce/features/products/presentation/widgets/message_display_widget.dart'; +import 'package:ecommernce/features/purchase/data/datasourcses/purchase_remote_datasource.dart'; +import 'package:ecommernce/features/purchase/data/repositories/purchase_repository_impl.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/features/purchase/domain/usecases/get_sales.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/sales/sales_bloc.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/sales/sales_events.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/sales/sales_state.dart'; +import 'package:ecommernce/features/purchase/presentation/widgets/sales_page/sales_list_widget.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; + +class slSalePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MultiBlocProvider(providers: [ + BlocProvider(create: (_) { + return SalesBloc( + getSales: GetSalesUsecase( + repository: PurchaseRepositoryImpl( + networkInfo: NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: PurchaseRemoteDataSourceImpl()))); + }) + ], child: sfSalePage()); + } +} + +class sfSalePage extends StatefulWidget { + @override + State createState() { + return stateSalePage(); + } +} + +class stateSalePage extends State { + late List sales; + + @override + void initState() { + if (FirebaseAuth.instance.currentUser != null) { + BlocProvider.of(context).add( + GetSalesEvent(userId: FirebaseAuth.instance.currentUser!.email!)); + } + + super.initState(); + } + + @override + Widget build(BuildContext context) { + // sales = salesProvider.getWatch(context).sales; + //print(sales.length); + + final totalHeight = MediaQuery.of(context).size.height; + final totalWidth = MediaQuery.of(context).size.width; + + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: Text("Sales History"), + ), + body: Container( + height: totalHeight, + width: totalWidth, + color: Color(0xffd3faff), + child: Column( + children: [ + SizedBox( + height: 40, + ), + Container( + height: totalHeight / 1.249, + child: FirebaseAuth.instance.currentUser != null + ? BlocBuilder( + builder: (context, state) { + if (state is LoadedSalesState) { + return SalesListWidget(totalWidth, totalHeight, + sales: sales); + } else if (state is ErrorSalesState) { + return MessageDisplayWidget(message: state.message); + } + return LoadingWidget(); + }) + : Center( + child: Text( + "You must to log in", + style: TextStyle(fontSize: 20), + )), + ), + ], + ), + )); + } +} diff --git a/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/cross_out_container.dart b/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/cross_out_container.dart new file mode 100644 index 0000000..4b9fc06 --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/cross_out_container.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; + +class CrossedOutContainer extends StatelessWidget { + Widget child; + bool isDeleted; + + CrossedOutContainer(this.child, this.isDeleted, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return CustomPaint( + painter: _CrossedOutPainter(isDeleted), + child: Container( + child: child, + ), + ); + } +} + +class _CrossedOutPainter extends CustomPainter { + bool isDeleted; + _CrossedOutPainter(this.isDeleted); + @override + void paint(Canvas canvas, Size size) { + if (isDeleted) { + Paint paint = Paint() + ..color = Colors.red + ..strokeWidth = 2.0; + + canvas.drawLine( + Offset(0, size.height / 2), + Offset(size.width, size.height / 2), + paint, + ); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/expandable_tile_widget.dart b/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/expandable_tile_widget.dart new file mode 100644 index 0000000..4e8e9a6 --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/expandable_tile_widget.dart @@ -0,0 +1,146 @@ +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/purchase/purchase_cubit.dart'; +import 'package:ecommernce/features/purchase/presentation/widgets/check_out_page/one_item_quantity_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +Widget BuildExpandableTile( + {required Purchase purchase, + required BuildContext context, + required String quan}) { + List detalisWidgets = []; + detalisWidgets.add(ListTile( + contentPadding: EdgeInsets.symmetric(horizontal: 60), + leading: Text('Color'), + title: Text('Size'), + trailing: Text('Quantity'), + )); + purchase.detalis!.forEach((key, value) { + detalisWidgets.add(ListTile( + contentPadding: EdgeInsets.symmetric(horizontal: 60), + title: Text(key.toString().substring(0, 2)), + leading: Container( + height: 40, + width: 30, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(int.parse(key.toString().substring(2)))), + ), + trailing: Text(value), + )); + }); + return ExpansionTile( + leading: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.keyboard_arrow_right_outlined), + Container( + width: 40, + height: 40, + child: ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8.0), + bottomLeft: Radius.circular(8.0), + ), + child: Image.network(purchase.p!.images![0], + fit: BoxFit.fitHeight), + )), + ], + ), + title: Text( + "Product: " + purchase.p!.name!, + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600), + ), + subtitle: Text( + "Quantity: " + purchase.quantity!, + style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600), + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "\$" + purchase.p!.cost!.toString(), + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), + ), + SizedBox(width: 10), + GestureDetector( + child: Icon( + Icons.edit, + color: Colors.cyan, + ), + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + List ll = []; + purchase.detalis!.forEach((key, value) { + ll.add(oneItemQuantity( + key, + int.parse(key.toString().substring(2)), + key.toString().substring(0, 2), + value)); + }); + quan = purchase.quantity!; + return AlertDialog( + title: Text("Edit Quantity"), + content: + StatefulBuilder /*to make setstate inside showDaialog possiple*/ ( + builder: ((context, setState) { + return Column( + mainAxisSize: MainAxisSize.min, + children: ll, + ); + })), + actions: [ + OutlinedButton( + onPressed: () async { + BlocProvider.of(context) + .editQuantity(purchase, ll); + + Navigator.pop(context); + }, + child: Text("Done")), + ], + ); + }, + ); + }), + SizedBox(width: 10), + GestureDetector( + child: Icon( + Icons.delete, + color: Colors.red, + ), + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text("Remove Item"), + content: Text("Do You Want To Remove This Item"), + actions: [ + OutlinedButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text("no")), + OutlinedButton( + onPressed: () async { + BlocProvider.of(context) + .minusFromTotal(int.parse(purchase.p!.cost!) * + int.parse(purchase.quantity!)); + BlocProvider.of(context) + .removeFromPurchase(purchase); + + Navigator.pop(context); + }, + child: Text("yes")), + ], + ); + }, + ); + }), + ], + ), + children: detalisWidgets); +} diff --git a/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/one_item_quantity_widget.dart b/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/one_item_quantity_widget.dart new file mode 100644 index 0000000..7d1fee4 --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/one_item_quantity_widget.dart @@ -0,0 +1,92 @@ +import 'package:ecommernce/features/purchase/presentation/pages/check_out_page.dart'; +import 'package:ecommernce/features/purchase/presentation/widgets/check_out_page/cross_out_container.dart'; +import 'package:flutter/material.dart'; + +class oneItemQuantity extends StatefulWidget { + var color; + var size; + var quantity; + var keyMap; + bool isDeleted = false; + oneItemQuantity(this.keyMap, this.color, this.size, this.quantity, {Key? key}) + : super(key: key); + + @override + State createState() => _oneItemQuantityState(); +} + +class _oneItemQuantityState extends State { + @override + Widget build(BuildContext context) { + return CrossedOutContainer( + ListTile( + leading: Container( + height: 40, + width: 30, + decoration: BoxDecoration( + + //border: + shape: BoxShape.circle, + color: Color(widget.color)), + ), + title: Text( + widget.size, + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + GestureDetector( + onTap: () { + int quan = int.parse(widget.quantity); + quan++; + setState(() { + widget.quantity = quan.toString(); + }); + }, + child: Icon( + Icons.arrow_circle_up, + size: 20, + ), + ), + Container( + alignment: Alignment.center, + height: 30, + width: 30, + child: Text(widget.quantity)), + GestureDetector( + onTap: () { + int quan = int.parse(widget.quantity); + if (quan == 1) { + return; + } + quan--; + setState(() { + widget.quantity = quan.toString(); + }); + }, + child: Icon( + Icons.arrow_circle_down, + size: 20, + ), + ), + SizedBox(width: 20), + GestureDetector( + onTap: () { + setState(() { + widget.isDeleted = !widget.isDeleted; + // print(widget.isDeleted); + }); + }, + child: Icon( + Icons.delete, + color: Colors.red, + size: 20, + ), + ), + ], + ), + ), + widget.isDeleted, + ); + } +} diff --git a/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/pay_with_paypal_button.dart b/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/pay_with_paypal_button.dart new file mode 100644 index 0000000..dec7549 --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/widgets/check_out_page/pay_with_paypal_button.dart @@ -0,0 +1,69 @@ +import 'package:ecommernce/core/firebase_services.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/purchase/purchase_cubit.dart'; +import 'package:ecommernce/features/purchase/presentation/pages/paypal_payment.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +Widget PayWithPaypalButton( + {required List pur, + required BuildContext context, + required List items}) { + return ElevatedButton( + //color: Colors.red, + onPressed: () { + for (Purchase p in pur) { + var item = { + 'name': p.p!.name!, + 'quantity': p.quantity, + 'price': p.p!.cost, + 'url': p.p!.images![0], + }; + items.add(item); + } + + Navigator.of(context) + .push( + MaterialPageRoute( + builder: (BuildContext context) => Payment( + items: items, + onFinish: (number) async { + // payment done + print("DDDDOOOONNNEEE"); + + final snackBar = SnackBar( + content: Text("Payment done Successfully"), + duration: Duration(seconds: 5), + action: SnackBarAction( + label: 'Close', + onPressed: () { + // Some code to undo the change. + }, + ), + ); + // _scaffoldKey.currentState + // ! + //.showSnackBar(snackBar); + print('order id: ' + number); + print('ddasdas'); + }, + ), + ), + ) + .then((value) { + firebaseServices().addToProfits(pur); + firebaseServices().increaseTimes(pur); + firebaseServices() + .addToSales(FirebaseAuth.instance.currentUser!.email!, pur); + }).then((value) { + BlocProvider.of(context).clearPurchase(); + }); + }, + child: Text( + 'Pay with Paypal', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white), + ), + ); +} diff --git a/ecommerce/lib/features/purchase/presentation/widgets/sales_page/sale_item.dart b/ecommerce/lib/features/purchase/presentation/widgets/sales_page/sale_item.dart new file mode 100644 index 0000000..b080ab0 --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/widgets/sales_page/sale_item.dart @@ -0,0 +1,89 @@ +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/model/product.dart'; +import 'package:ecommernce/model/purchase.dart'; +import 'package:flutter/material.dart'; + +Widget SaleItem( + BuildContext context, double totalHeight, double totalWidth, Purchase pur) { + //print(pro.daydate! + " z " + pro.daytime.toString()); + return GestureDetector( + child: Container( + height: totalHeight / 8, + margin: EdgeInsets.symmetric( + horizontal: MediaQuery.of(context).size.width / 20), + child: Container( + margin: EdgeInsets.symmetric(vertical: 5), + child: Card( + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + child: Container( + child: Row( + children: [ + Container( + width: totalWidth / 4, + child: ClipRRect( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(8.0), + bottomLeft: Radius.circular(8.0), + ), + child: + Image.network(pur.p!.images![0], fit: BoxFit.fill), + )), + Container( + width: totalWidth / 4, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + child: Center( + child: Text( + "${pur.p!.name!}", + style: TextStyle(fontSize: 12, fontFamily: "New"), + )), + ), + Container( + child: Center( + child: Text( + "${pur.quantity}", + style: TextStyle(fontSize: 12, fontFamily: "New"), + )), + ), + Container( + child: Center( + child: Text("\$" + pur.p!.cost!, + style: TextStyle( + fontSize: 13, fontFamily: "New"))), + ), + ], + ), + ), + Container( + width: MediaQuery.of(context).size.width / 2 / 3 * 2 - 9, + child: Column( + children: [ + Container( + height: totalHeight / 20, + child: Center( + child: Text( + pur.p!.daydate!, + style: TextStyle(fontSize: 12, fontFamily: "New"), + )), + ), + Container( + height: totalHeight / 20, + child: Center( + child: Text(pur.p!.daytime!, + style: const TextStyle( + fontSize: 12, fontFamily: "New"))), + ), + ], + ), + ), + ], + ), + ), + ), + )), + onTap: () {}, + ); +} diff --git a/ecommerce/lib/features/purchase/presentation/widgets/sales_page/sales_list_widget.dart b/ecommerce/lib/features/purchase/presentation/widgets/sales_page/sales_list_widget.dart new file mode 100644 index 0000000..904687b --- /dev/null +++ b/ecommerce/lib/features/purchase/presentation/widgets/sales_page/sales_list_widget.dart @@ -0,0 +1,20 @@ +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/features/purchase/presentation/widgets/sales_page/sale_item.dart'; +import 'package:flutter/material.dart'; + +Widget SalesListWidget(totalWidth, totalHeight, + {required List sales}) { + return ListView.builder( + physics: BouncingScrollPhysics(), + itemCount: sales.length, + itemBuilder: (context, index) { + final pur = sales[index]; + + return SaleItem( + context, + totalHeight, + totalWidth, + pur, + ); + }); +} diff --git a/ecommerce/lib/features/reviews/data/datasources/reviews_remote_datasource.dart b/ecommerce/lib/features/reviews/data/datasources/reviews_remote_datasource.dart new file mode 100644 index 0000000..1fccb9f --- /dev/null +++ b/ecommerce/lib/features/reviews/data/datasources/reviews_remote_datasource.dart @@ -0,0 +1,59 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:ecommernce/features/reviews/data/models/review_model.dart'; + +abstract class ReviewsRemoteDataSource { + Future> getAllReviews({required String productId}); + Future getBestReview({required String productId}); +} + +class ReviewsRemoteDataSourceImpl implements ReviewsRemoteDataSource { + ReviewsRemoteDataSourceImpl(); + + @override + Future> getAllReviews({required String productId}) async { + List reviews = []; + CollectionReference ref1 = + FirebaseFirestore.instance.collection("products"); + QuerySnapshot qsshReviews = + await ref1.doc(productId).collection('reviews').get(); + List listdocsReviews = qsshReviews.docs; + listdocsReviews.forEach((element) { + ReviewModel toAddReview = ReviewModel( + text: element['text'], + id: element['id'], + name: element['name'], + rating: element['rating'], + date: element['date'], + ); + reviews.add(toAddReview); + }); + return reviews; + } + + @override + Future getBestReview({required productId}) async { + ReviewModel bestReview = ReviewModel(); + //print("getting best"); + CollectionReference ref1 = + FirebaseFirestore.instance.collection("products"); + QuerySnapshot qsshReviews = await ref1 + .doc(productId) + .collection('reviews') + .orderBy('rating', descending: true) + .limit(1) + .get(); + List listdocs = + qsshReviews.docs; // وهان بنحطهم ك list + listdocs.forEach((element) { + print(element); + bestReview = ReviewModel( + text: element['text'], + id: element['id'], + name: element['name'], + rating: element['rating'], + date: element['date'], + ); + }); + return bestReview; + } +} diff --git a/ecommerce/lib/features/reviews/data/models/review_model.dart b/ecommerce/lib/features/reviews/data/models/review_model.dart new file mode 100644 index 0000000..988b392 --- /dev/null +++ b/ecommerce/lib/features/reviews/data/models/review_model.dart @@ -0,0 +1,32 @@ +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; + +class ReviewModel extends Review { + ReviewModel( + {String? id, String? name, String? text, String? date, String? rating}) + : super( + id: id, + name: name, + text: text, + date: date, + rating: rating, + ); + factory ReviewModel.fromJson(Map json) { + return ReviewModel( + id: json['id'], + name: json['name'], + text: json['text'], + date: json['date'], + rating: json['rating'], + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'text': text, + 'date': date, + 'rating': rating + }; + } +} diff --git a/ecommerce/lib/features/reviews/data/repositories/review_repository_imp.dart b/ecommerce/lib/features/reviews/data/repositories/review_repository_imp.dart new file mode 100644 index 0000000..bbc8f26 --- /dev/null +++ b/ecommerce/lib/features/reviews/data/repositories/review_repository_imp.dart @@ -0,0 +1,49 @@ +import 'package:ecommernce/core/errors/exceptions.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/features/reviews/data/datasources/reviews_remote_datasource.dart'; +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; +import 'package:ecommernce/features/reviews/domain/repositories/review_reposaitory.dart'; + +class ReviewsRepositoryImpl implements ReviewsRepository { + final ReviewsRemoteDataSourceImpl remoteDataSource; + //final ProductsLocalDataSource localDataSource; + final NetworkInfo networkInfo; + ReviewsRepositoryImpl({ + required this.remoteDataSource, + //required this.localDataSource, + required this.networkInfo, + }); + + @override + Future>> getAllReveiws( + {required String productId}) async { + if (await networkInfo.isConnected) { + try { + final remoteReviews = + await remoteDataSource.getAllReviews(productId: productId); + print('getAllReveiws remote' + remoteReviews.length.toString()); + // localDataSource.cacheFavorites(remotePosts); + return Right(remoteReviews); + } on ServerException { + return Left(ServerFailure()); + } + } else { + return Right([]); + } + } + + @override + Future> getBestReview({required productId}) async { + try { + final remoteBestReview = + await remoteDataSource.getBestReview(productId: productId); + print('remoteBestReview remote' + remoteBestReview.toString()); + // localDataSource.cacheFavorites(remotePosts); + return Right(remoteBestReview); + } on ServerException { + return Left(ServerFailure()); + } + } +} diff --git a/ecommerce/lib/features/reviews/domain/entities/review.dart b/ecommerce/lib/features/reviews/domain/entities/review.dart new file mode 100644 index 0000000..4b7559b --- /dev/null +++ b/ecommerce/lib/features/reviews/domain/entities/review.dart @@ -0,0 +1,15 @@ +import 'package:equatable/equatable.dart'; + +class Review extends Equatable { + String? id; + String? name; + String? text; + String? date; + String? rating; + + Review({this.id, this.name, this.text, this.date, this.rating}); + + @override + // TODO: implement props + List get props => [id, name, text, date, rating]; +} diff --git a/ecommerce/lib/features/reviews/domain/repositories/review_reposaitory.dart b/ecommerce/lib/features/reviews/domain/repositories/review_reposaitory.dart new file mode 100644 index 0000000..3e1c17c --- /dev/null +++ b/ecommerce/lib/features/reviews/domain/repositories/review_reposaitory.dart @@ -0,0 +1,10 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; + +abstract class ReviewsRepository { + Future>> getAllReveiws( + {required String productId}); + Future> getBestReview({required productId}); +} diff --git a/ecommerce/lib/features/reviews/domain/usecases/get_all_reviews.dart b/ecommerce/lib/features/reviews/domain/usecases/get_all_reviews.dart new file mode 100644 index 0000000..6f17c34 --- /dev/null +++ b/ecommerce/lib/features/reviews/domain/usecases/get_all_reviews.dart @@ -0,0 +1,18 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/repositories/product_repository.dart'; +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; +import 'package:ecommernce/features/reviews/domain/repositories/review_reposaitory.dart'; + +class GetAllReviewsUsecase { + final ReviewsRepository repository; + + GetAllReviewsUsecase({required this.repository}); + + Future>> call( + {required String productId}) async { + print('GetAllReviewsUsecase'); + return await repository.getAllReveiws(productId: productId); + } +} diff --git a/ecommerce/lib/features/reviews/domain/usecases/get_best_review.dart b/ecommerce/lib/features/reviews/domain/usecases/get_best_review.dart new file mode 100644 index 0000000..335b6d0 --- /dev/null +++ b/ecommerce/lib/features/reviews/domain/usecases/get_best_review.dart @@ -0,0 +1,17 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/repositories/product_repository.dart'; +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; +import 'package:ecommernce/features/reviews/domain/repositories/review_reposaitory.dart'; + +class GetBestReviewUsecase { + final ReviewsRepository repository; + + GetBestReviewUsecase({required this.repository}); + + Future> call({required productId}) async { + print('GetBestReviewUsecase'); + return await repository.getBestReview(productId: productId); + } +} diff --git a/ecommerce/lib/features/reviews/presentation/bloc/review/review_bloc.dart b/ecommerce/lib/features/reviews/presentation/bloc/review/review_bloc.dart new file mode 100644 index 0000000..d97a35b --- /dev/null +++ b/ecommerce/lib/features/reviews/presentation/bloc/review/review_bloc.dart @@ -0,0 +1,79 @@ +import 'package:dartz/dartz.dart'; +import 'package:ecommernce/core/errors/failures.dart'; +import 'package:ecommernce/core/strings/failures.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_favorites.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_populars.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_state.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_events.dart'; +import 'package:ecommernce/features/products/presentation/bloc/populars/populars_state.dart'; +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; +import 'package:ecommernce/features/reviews/domain/usecases/get_all_reviews.dart'; +import 'package:ecommernce/features/reviews/domain/usecases/get_best_review.dart'; +import 'package:ecommernce/features/reviews/presentation/bloc/review/review_events.dart'; +import 'package:ecommernce/features/reviews/presentation/bloc/review/review_state.dart'; +import 'package:equatable/equatable.dart'; + +import 'package:flutter_bloc/flutter_bloc.dart'; + +class ReviewsBloc extends Bloc { + final GetAllReviewsUsecase getAllReviews; + final GetBestReviewUsecase getBestreview; + ReviewsBloc({ + required this.getAllReviews, + required this.getBestreview, + }) : super(ReviewsInitial()) { + on((event, emit) async { + if (event is GetAllReviewsEvent) { + emit(LoadingReviewsState()); + + final failureOrPosts = await getAllReviews(productId: event.productId); + emit(_mapFailureOrAllReviewsToState( + failureOrPosts as Either>)); + } else if (event is GetBestReviewEvent) { + emit(LoadingReviewsState()); + + final failureOrPosts = await getBestreview(productId: event.productId); + emit(_mapFailureOrBestReviewToState( + failureOrPosts as Either)); + } + }); + } + + ReviewsState _mapFailureOrAllReviewsToState( + Either> either) { + return either.fold((failure) { + print("fffff"); + return ErrorReviewsState(message: _mapFailureToMessage(failure)); + }, (allReviews) { + print("yyyyyyy " + allReviews.length.toString()); + return LoadedReviewsState(allReviews: allReviews); + }); + } + + ReviewsState _mapFailureOrBestReviewToState(Either either) { + return either.fold((failure) { + print("fffff"); + return ErrorReviewsState(message: _mapFailureToMessage(failure)); + }, (bestReview) { + print("yyyyyyy " + bestReview.toString()); + return LoadedBestReviewState( + bestReview: bestReview, + ); + }); + } + + String _mapFailureToMessage(Failure failure) { + switch (failure.runtimeType) { + case ServerFailure: + return SERVER_FAILURE_MESSAGE; + case EmptyCacheFailure: + return EMPTY_CACHE_FAILURE_MESSAGE; + case OfflineFailure: + return OFFLINE_FAILURE_MESSAGE; + default: + return "Unexpected Error , Please try again later ."; + } + } +} diff --git a/ecommerce/lib/features/reviews/presentation/bloc/review/review_events.dart b/ecommerce/lib/features/reviews/presentation/bloc/review/review_events.dart new file mode 100644 index 0000000..5bde7bc --- /dev/null +++ b/ecommerce/lib/features/reviews/presentation/bloc/review/review_events.dart @@ -0,0 +1,26 @@ +//part of 'favorites_bloc.dart'; + +import 'package:equatable/equatable.dart'; + +abstract class ReviewsEvent extends Equatable { + const ReviewsEvent(); + + @override + List get props => []; +} + +class GetAllReviewsEvent extends ReviewsEvent { + String productId; + GetAllReviewsEvent(this.productId); + + @override + List get props => [productId]; +} + +class GetBestReviewEvent extends ReviewsEvent { + String productId; + GetBestReviewEvent(this.productId); + + @override + List get props => [productId]; +} diff --git a/ecommerce/lib/features/reviews/presentation/bloc/review/review_state.dart b/ecommerce/lib/features/reviews/presentation/bloc/review/review_state.dart new file mode 100644 index 0000000..1a54f98 --- /dev/null +++ b/ecommerce/lib/features/reviews/presentation/bloc/review/review_state.dart @@ -0,0 +1,40 @@ +//part of 'favorites_bloc.dart'; +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; + +abstract class ReviewsState { + const ReviewsState(); + + @override + List get props => []; +} + +class ReviewsInitial extends ReviewsState {} + +class LoadingReviewsState extends ReviewsState {} + +class LoadedReviewsState extends ReviewsState { + final List allReviews; + + LoadedReviewsState({required this.allReviews}); + + @override + List get props => [allReviews]; +} + +class LoadedBestReviewState extends ReviewsState { + final Review bestReview; + + LoadedBestReviewState({required this.bestReview}); + + @override + List get props => [bestReview]; +} + +class ErrorReviewsState extends ReviewsState { + final String message; + + ErrorReviewsState({required this.message}); + + @override + List get props => [message]; +} diff --git a/ecommerce/lib/features/reviews/presentation/pages/review_page.dart b/ecommerce/lib/features/reviews/presentation/pages/review_page.dart new file mode 100644 index 0000000..4bfffb1 --- /dev/null +++ b/ecommerce/lib/features/reviews/presentation/pages/review_page.dart @@ -0,0 +1,55 @@ +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; +import 'package:ecommernce/features/reviews/presentation/widgets/review_page/reviews_list_widget.dart'; +import 'package:flutter/material.dart'; + +class slReviewsPage extends StatelessWidget { + List reviews; + //String id; + slReviewsPage({Key? key, required this.reviews}) : super(key: key); + + @override + Widget build(BuildContext context) { + return sfReviewsPage(reviews: reviews); + } +} + +class sfReviewsPage extends StatefulWidget { + //String id; + List reviews; + sfReviewsPage({Key? key, required this.reviews}) : super(key: key); + + @override + State createState() => stateReviewsPage(); +} + +class stateReviewsPage extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: Text("Reviews"), + ), + body: Container( + //height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + color: Color(0xffd3faff), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 40, + ), + Container( + height: MediaQuery.of(context).size.height - + AppBar().preferredSize.height - + 40 - + 34, + color: Color(0xffd3faff), + child: reviewsListWidget(widget.reviews)) + ], + ), + ), + ); + } +} diff --git a/ecommerce/lib/features/reviews/presentation/widgets/review_page/one_review_widget.dart b/ecommerce/lib/features/reviews/presentation/widgets/review_page/one_review_widget.dart new file mode 100644 index 0000000..080d911 --- /dev/null +++ b/ecommerce/lib/features/reviews/presentation/widgets/review_page/one_review_widget.dart @@ -0,0 +1,76 @@ +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; +import 'package:flutter/material.dart'; +import 'package:smooth_star_rating/smooth_star_rating.dart'; + +Widget oneReview(Review rev) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 10), + margin: EdgeInsets.symmetric(vertical: 10), + //height: 50, + child: Column( + children: [ + Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), + // height: 70, + width: 300, + color: Colors.white54, + child: Column( + children: [ + Row( + children: [ + Expanded( + child: Container( + padding: EdgeInsets.only(left: 15, top: 10), + alignment: Alignment.topLeft, + child: Text( + rev.date!, + style: TextStyle(fontSize: 10, fontFamily: "New"), + ), + ), + ), + Expanded( + child: Container( + padding: EdgeInsets.only(right: 15, top: 10), + alignment: Alignment.topRight, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SmoothStarRating( + rating: double.parse(rev.rating!), + size: 12, + starCount: 5, + ), + Text( + ' ' + rev.rating!, + style: TextStyle(fontSize: 11, fontFamily: "New"), + textAlign: TextAlign.end, + ), + ], + ), + ), + ) + ], + ), + Container( + padding: EdgeInsets.only(left: 15, top: 5), + alignment: Alignment.topLeft, + child: Text( + "${rev.name} :", + style: TextStyle(fontSize: 13, fontFamily: "New"), + ), + ), + Container( + padding: EdgeInsets.only(left: 15, top: 5), + alignment: Alignment.topLeft, + child: Text( + rev.text!, + style: TextStyle(fontSize: 11, fontFamily: "New"), + ), + ), + ], + ), + ) + ], + ), + ); +} diff --git a/ecommerce/lib/features/reviews/presentation/widgets/review_page/reviews_list_widget.dart b/ecommerce/lib/features/reviews/presentation/widgets/review_page/reviews_list_widget.dart new file mode 100644 index 0000000..4a9e9aa --- /dev/null +++ b/ecommerce/lib/features/reviews/presentation/widgets/review_page/reviews_list_widget.dart @@ -0,0 +1,13 @@ +import 'package:ecommernce/features/reviews/domain/entities/review.dart'; +import 'package:ecommernce/features/reviews/presentation/widgets/review_page/one_review_widget.dart'; +import 'package:flutter/material.dart'; + +Widget reviewsListWidget(List reviews) { + return ListView.builder( + physics: BouncingScrollPhysics(), + itemCount: reviews.length, + itemBuilder: (context, index) { + final review = reviews[index]; + return oneReview(review); + }); +} diff --git a/ecommerce/lib/firebase.dart b/ecommerce/lib/firebase.dart new file mode 100644 index 0000000..ad73eb5 --- /dev/null +++ b/ecommerce/lib/firebase.dart @@ -0,0 +1,199 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:ecommernce/features/purchase/domain/entites/purchase.dart'; +import 'package:ecommernce/model/product.dart'; +import 'package:ecommernce/model/purchase.dart'; +import 'package:ecommernce/model/user.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'model/user.dart'; + +class firebase extends ChangeNotifier { + List sales = []; + List allProducts = []; + List allUsers = []; + + static firebase getWatch(BuildContext context) { + //print("watch"); + return context.watch(); + } + + static firebase getRead(BuildContext context) { + //print("read"); + return context.read(); + } + + Future> getAll() async { + allProducts.clear(); + print("hh"); + CollectionReference ref = FirebaseFirestore.instance.collection("products"); + QuerySnapshot qssh = await ref.get(); // هان برجع كبشة documents + List listdocs = qssh.docs; // وهان بنحطهم ك list + listdocs.forEach((element) { + product toAdd = product( + name: element["name"], + id: element["id"], + type: element["type"], + times: element["times"], + cost: element["cost"], + description: element["description"], + images: element["images"]); + allProducts.add(toAdd); + }); + try { + notifyListeners(); + } catch (e) { + print(e); + } + return allProducts; + } + + Future> getAllUsers() async { + allUsers.clear(); + CollectionReference ref = FirebaseFirestore.instance.collection("users"); + QuerySnapshot qssh = await ref.get(); // هان برجع كبشة documents + List listdocs = qssh.docs; // وهان بنحطهم ك list + listdocs.forEach((element) { + user toAdd = user( + name: element["name"], + id: element["id"], + password: element["password"], + ); + allUsers.add(toAdd); + }); + try { + notifyListeners(); + } catch (e) { + print(e); + } + return allUsers; + } + + /*Future> getSales(String id) async { + sales.clear(); + CollectionReference ref = FirebaseFirestore.instance.collection("products"); + CollectionReference ref2 = FirebaseFirestore.instance + .collection("users") + .doc(id) + .collection("sales"); + QuerySnapshot qsshid = await ref2 + .orderBy("rank", descending: true) + .get(); // هان برجع كبشة documents + List listid = qsshid.docs; // وهان بنحطهم ك list + List ids = []; + listid.forEach((elementt) { + String id = elementt["id"]; + String time = elementt["daytime"]; + String date = elementt["daydate"]; + product p = product(id: id, daydate: date, daytime: time); + ids.add(p); + }); + ids.forEach((elemente) async { + QuerySnapshot qsshpro = + await ref.where("id", isEqualTo: elemente.id).get(); + if (qsshpro.docs.isEmpty) { + } else { + final element = qsshpro.docs[0]; + product toAdd = product( + daydate: elemente.daydate, + daytime: elemente.daytime, + name: element["name"], + id: element["id"], + type: element["type"], + times: element["times"], + cost: element["cost"], + description: element["description"], + url: element["url"]); + sales.add(toAdd); + try { + notifyListeners(); + } catch (e) {} + } + }); + return sales; + } +*/ + void refreshSales() { + sales.clear(); + // getSales(signInProvider().us!.id!); + } + + void refreshAll() { + allProducts.clear(); + getAll(); + } + + void refreshAllUsers() { + allUsers.clear(); + getAll(); + } +} + +/*class firebaseServices { + firebaseServices(); + + void increaseTimes(List pur) { + for (var p in pur) { + int purTimes = int.parse(p.quantity!); + + FirebaseFirestore.instance + .collection("products") + .doc(p.p!.id!) + .get() + .then((value) { + var data = value.data() as Map; + int oldTimes = int.parse(data['times']); + int newTimes = purTimes += oldTimes; + FirebaseFirestore.instance + .collection("products") + .doc(p.p!.id!) + .update({'times': newTimes.toString()}); + }); + } + } + + void addToSales(String id, List pur) { + String daydate = DateFormat("yyyy-MM-dd").format(DateTime.now()); + String dattime = DateFormat("HH:mm:ss").format(DateTime.now()); + for (purchase r in pur) { + FirebaseFirestore.instance + .collection("users") + .doc(id) + .collection('sales') + .add({ + "id": r.p!.id, + "name": r.p!.name, + "cost": r.p!.cost, + "quantity": r.quantity, + "image": r.p!.images![0], + "daytime": dattime, + "daydate": daydate, + }); + } + } + + void addToProfits(List pur) { + int total = 0; + for (var p in pur) { + int purCost = int.parse(p.p!.cost!) * int.parse(p.quantity!); + total += purCost; + print("${p.p!.name!} " + purCost.toString()); + // print("${p.p!.name!} newProfits " + newProfits.toString()); + } + + CollectionReference ref3 = FirebaseFirestore.instance.collection("profits"); + ref3.get().then((value) { + final prof = value.docs[0]["total"]; + final profid = value.docs[0]["id"]; + + int curprof = int.parse(prof); + print("curprof " + curprof.toString()); + int plusprof = curprof + total; + print("plusprof " + plusprof.toString()); + ref3.doc(profid).update({"total": plusprof.toString()}); + }); + } +} +*/ \ No newline at end of file diff --git a/ecommerce/lib/main.dart b/ecommerce/lib/main.dart new file mode 100644 index 0000000..35935ec --- /dev/null +++ b/ecommerce/lib/main.dart @@ -0,0 +1,78 @@ +import 'package:ecommernce/core/network/network_info.dart'; +import 'package:ecommernce/core/widgets/custom_drawer.dart'; +import 'package:ecommernce/features/auth/auth_provider.dart'; +import 'package:ecommernce/features/products/data/datasources/products_local_datasource.dart'; +import 'package:ecommernce/features/products/data/datasources/products_remote_datasource.dart'; +import 'package:ecommernce/features/products/data/repositories/product_repository_imp.dart'; +import 'package:ecommernce/features/products/domain/usecases/get_favorites.dart'; +import 'package:ecommernce/features/products/presentation/bloc/favortites/favorites_bloc.dart'; +import 'package:ecommernce/features/purchase/presentation/bloc/purchase/purchase_cubit.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:provider/provider.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:ecommernce/cache/sharedPreferences.dart'; + +Future main() async { + Provider.debugCheckInvalidValueType = null; + WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp(); + await sharedPreferences.init(); + runApp(slRunApp()); +} + +class slRunApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MultiProvider( + providers: [ + Provider( + create: (_) { + return signInProvider(FirebaseAuth.instance); + }, + ), + StreamProvider( + create: (context) { + return context.read().authStateChenges; + }, + initialData: null, + ), + ], + child: MultiBlocProvider( + providers: [ + BlocProvider(create: (_) { + return FavoritesBloc( + getAllFavorites: GetFavoritesUsecase( + repository: ProductsRepositoryImpl( + localDataSource: ProductsLocalDataSourceImpl(), + networkInfo: + NetworkInfoImpl(InternetConnectionChecker()), + remoteDataSource: ProductsRemoteDataSourceImpl()))); + }), + BlocProvider(create: (_) { + return PurchaseCubit(); + }) + ], + child: MaterialApp( + home: slUser(), debugShowCheckedModeBanner: false))); + } +} + +class slUser extends StatelessWidget { + @override + Widget build(BuildContext context) { + final firebaseUser = context.watch(); + return CustomDrawer( + //controller: _drawerController, + //mainScreen: slMainPage(_drawerController), + //menuScreen: slSettingsPage(_drawerController), + showShadow: false, + angle: 0.0, + borderRadius: 30, + slideWidth: MediaQuery.of(context).size.width * + (CustomDrawer.isRTL(context) ? 0.45 : 0.70), + ); + } +} diff --git a/ecommerce/lib/mainPage.dart b/ecommerce/lib/mainPage.dart new file mode 100644 index 0000000..5a76eb8 --- /dev/null +++ b/ecommerce/lib/mainPage.dart @@ -0,0 +1,125 @@ +import 'package:ecommernce/core/widgets/custom_drawer.dart'; +import 'package:ecommernce/features/products/presentation/pages/home_page.dart'; +import 'package:ecommernce/features/purchase/presentation/pages/check_out_page.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; + +class slMainPage extends StatelessWidget { + CustomDrawerController drawerController; + slMainPage(this.drawerController, {Key? key}) : super(key: key); + @override + Widget build(BuildContext context) { + return sfMainPage(drawerController); + } +} + +class sfMainPage extends StatefulWidget { + CustomDrawerController drawerController; + sfMainPage(this.drawerController, {Key? key}) : super(key: key); + @override + State createState() => stateMainPage(); +} + +class stateMainPage extends State { + int _selectedIndex = 1; + static List _widgetOptions = [ + Container(), + slhomePage(), + CheckOutPage(), + //slSettingsPage() + ]; + + void _onItemTapped(int index) { + if (index == 0) { + widget.drawerController.toggle(); + return; + } + + setState(() { + _selectedIndex = index; + }); + } + + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 3, + child: Scaffold( + appBar: AppBar(), + body: SingleChildScrollView( + child: Center( + child: _widgetOptions[_selectedIndex], + ) + + /* Container( + child: Column( + children: [ + Container( + height: widgetHight, + child: AnimatedSwitcher( + duration: Duration(milliseconds: 300), + switchInCurve: Curves.easeInCubic, + switchOutCurve: Curves.easeOutBack, + child: whichPage()), + ), + Container( + color: Colors.blue, + height: 50, + child: Row( + children: [ + Expanded( + child: + iconWidget(0, Icons.home, s1, r1, cIcon1, cContainer1), + ), + Expanded( + child: iconWidget(1, Icons.shopping_cart_sharp, s2, r2, + cIcon2, cContainer2), + ), + Expanded( + child: iconWidget( + 2, Icons.favorite, s3, r3, cIcon3, cContainer3), + ), + ], + ), + ) + ], + ), + ),*/ + ), + bottomNavigationBar: homePageTabBar()), + ); + } + + BottomNavigationBar homePageTabBar() { + return BottomNavigationBar( + onTap: _onItemTapped, + currentIndex: _selectedIndex, + showSelectedLabels: false, + showUnselectedLabels: false, + //backgroundColor: bottomBarColor, + items: [ + BottomNavigationBarItem( + icon: Icon( + Icons.menu, + color: _selectedIndex == 0 ? Colors.red : Colors.blue, + ), + label: "", + ), + BottomNavigationBarItem( + icon: Icon( + Icons.home, + color: _selectedIndex == 1 ? Colors.red : Colors.blue, + ), + label: "", + ), + BottomNavigationBarItem( + icon: Icon( + Icons.monetization_on, + color: _selectedIndex == 2 ? Colors.red : Colors.blue, + ), + label: "", + ), + ], + ); + } +} diff --git a/ecommerce/lib/manegerAllProducts.dart b/ecommerce/lib/manegerAllProducts.dart new file mode 100644 index 0000000..486efcf --- /dev/null +++ b/ecommerce/lib/manegerAllProducts.dart @@ -0,0 +1,204 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import 'firebase.dart'; +import 'manegerProductAddOrEdit.dart'; +import 'model/product.dart'; + +class slManegerAllProducts extends StatelessWidget { + @override + Widget build(BuildContext context) { + return sfManegerAllProducts(); + } +} + +class sfManegerAllProducts extends StatefulWidget { + @override + State createState() { + return stateManegerAllProducts(); + } +} + +class stateManegerAllProducts extends State { + @override + Widget build(BuildContext context) { + var model2 = Provider.of(context, listen: true); + return FutureProvider>( + create: (BuildContext context) { + return context.read().getAll(); + }, + initialData: [], + child: Scaffold( + floatingActionButton: FloatingActionButton( + backgroundColor: Colors.red, + onPressed: () { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return slManegerProductDetalis(0, null); + })).then((value) { + model2.refreshAll(); + setState(() {}); + }); + }, + child: Icon(Icons.add), + ), + body: sfManegerAllProductsProvider(), + )); + } +} + +class sfManegerAllProductsProvider extends StatefulWidget { + @override + State createState() { + return stateManegerAllProductsProvider(); + } +} + +class stateManegerAllProductsProvider + extends State { + @override + Widget build(BuildContext context) { + var model2 = Provider.of(context, listen: true); + context.watch>(); + TextEditingController sch = TextEditingController(); + + final totalHeight = MediaQuery.of(context).size.height; + final totalWidth = MediaQuery.of(context).size.width; + return Container( + height: totalHeight, + width: totalWidth, + color: Color(0xffd3faff), + child: Column( + children: [ + SizedBox( + height: totalHeight / 16, + ), + Container( + child: TextField( + controller: sch, + onChanged: (value) async { + CollectionReference ref = + FirebaseFirestore.instance.collection("products"); + QuerySnapshot qssh = + await ref.where("name", isEqualTo: value).get(); + }, + ), + ), + Container( + height: totalHeight - (totalHeight / 8), + child: ListView.builder( + itemCount: model2.allProducts.length, + itemBuilder: (context, index) { + final prodct = model2.allProducts[index]; + product pro = product( + name: prodct.name, + id: prodct.id, + type: prodct.type, + times: prodct.times, + cost: prodct.cost, + description: prodct.description, + images: prodct.images); + return GestureDetector( + child: Container( + height: (MediaQuery.of(context).size.height - 146) / 4, + margin: EdgeInsets.symmetric( + horizontal: MediaQuery.of(context).size.width / 6), + child: Container( + margin: EdgeInsets.symmetric(vertical: 5), + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10)), + child: Container( + child: Row( + children: [ + Container( + width: MediaQuery.of(context).size.width / + 2 / + 3 * + 2, + height: + (MediaQuery.of(context).size.height - + 146) / + 4, + child: ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8.0), + bottomLeft: Radius.circular(8.0), + ), + child: Image.network(pro.images![0], + fit: BoxFit.fitHeight), + )), + // Container( + // color: Colors.blue, + // width: MediaQuery + // .of(context) + // .size + // .width / 2 / 3 * 2), + Container( + width: MediaQuery.of(context).size.width / + 2 / + 3 * + 2 - + 9, + child: Column( + children: [ + SizedBox( + height: ((MediaQuery.of(context) + .size + .height - + 146) / + 4 / + 4) - + 10), + Container( + height: ((MediaQuery.of(context) + .size + .height - + 146) / + 4 / + 3) - + 10, + child: Center( + child: Text( + pro.name!, + style: TextStyle(fontSize: 20), + )), + ), + Container( + height: ((MediaQuery.of(context) + .size + .height - + 146) / + 4 / + 3) - + 8, + child: Center( + child: Text("\$" + pro.cost!, + style: + TextStyle(fontSize: 30))), + ), + ], + ), + ), + ], + ), + ), + ), + )), + onTap: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return slManegerProductDetalis(1, pro); + })).then((value) { + model2.refreshAll(); + setState(() {}); + }); + }, + ); + }), + ) + ], + ), + ); + } +} diff --git a/ecommerce/lib/manegerAllProfits.dart b/ecommerce/lib/manegerAllProfits.dart new file mode 100644 index 0000000..35c2427 --- /dev/null +++ b/ecommerce/lib/manegerAllProfits.dart @@ -0,0 +1,96 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + + +class slManegerAllProfits extends StatelessWidget{ + @override + Widget build(BuildContext context) { + return sfManegerAllProfits(); + } +} + +class sfManegerAllProfits extends StatefulWidget{ + @override + State createState() { + return stateManegerAllProfits(); + } +} + +class stateManegerAllProfits extends State{ + @override + Widget build(BuildContext context) { + final totalHeight=MediaQuery.of(context).size.height; + final totalWidth=MediaQuery.of(context).size.width; + return Scaffold( + body: Container( + height: totalHeight,width: totalWidth, + child: Column( + children: [ + SizedBox(height: totalHeight/10,), + profits(context), + SizedBox(height: totalHeight/40,), + ListTile(title: Text("name"),trailing: Text("times"),), + //SizedBox(height: totalHeight/40,), + times(context), + ], + ), + ), + ); + } + + Widget profits (BuildContext context){ + final totalHeight=MediaQuery.of(context).size.height; + final totalWidth=MediaQuery.of(context).size.width; + CollectionReference ref1=FirebaseFirestore.instance.collection("profits"); + return Container( + width: totalWidth/1.5,height: totalHeight/5, + color: Colors.blue, + child: Column( + children: [ + SizedBox(height: totalHeight/5/4,), + Text("Total Profits",style: TextStyle(fontSize: 25,color: Colors.white),), + SizedBox(height: totalHeight/5/8,), + StreamBuilder( + stream: ref1.snapshots(), + builder: (context,snapshot){ + if(snapshot.hasData) { + final profit=snapshot.data!.docs[0]["total"]; + return Text(profit,style: TextStyle(fontSize: 20,color: Colors.white),); + } + return Container(); + }, + ) + ], + ), + + ); + } + + Widget times(BuildContext context){ + final totalHeight=MediaQuery.of(context).size.height; + final totalWidth=MediaQuery.of(context).size.width; + CollectionReference ref1=FirebaseFirestore.instance.collection("products"); + return Container( + height: totalHeight/1.65,width: totalWidth, + child:StreamBuilder( + stream: ref1.orderBy("times",descending: true).snapshots(), + builder: (context,snapshot){ + if(snapshot.hasData) { + return ListView.builder( + itemCount: snapshot.data!.docs.length, + itemBuilder: (context, index) { + final pro = snapshot.data!.docs[index]; + return ListTile( + title: Text(pro["name"]), + trailing: Text(pro["times"]) + ); + }); + } + return Container(); + }, + ) + ); + } +} + diff --git a/ecommerce/lib/manegerAllUsers.dart b/ecommerce/lib/manegerAllUsers.dart new file mode 100644 index 0000000..ef0b9c5 --- /dev/null +++ b/ecommerce/lib/manegerAllUsers.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import 'firebase.dart'; +import 'model/user.dart'; + +class slManegerAllUsers extends StatelessWidget{ + @override + Widget build(BuildContext context) { + return sfManegerAllUsers(); + } +} + +class sfManegerAllUsers extends StatefulWidget{ + @override + State createState() { + return stateManegerAllUsers(); + } +} + +class stateManegerAllUsers extends State{ + @override + Widget build(BuildContext context) { + return FutureProvider>( + create: (BuildContext context) { + return context.read().getAllUsers(); + }, + initialData: [], + child: Scaffold( + body:sfManegerAllUsersProvider(), + ) + ); + } +} + +class sfManegerAllUsersProvider extends StatefulWidget{ + @override + State createState() { + return stateManegerAllUsersProvider(); + } + +} + +class stateManegerAllUsersProvider extends State{ + @override + Widget build(BuildContext context) { + var model2 = Provider.of(context,listen: true); + context.read>(); + + final totalHeight = MediaQuery + .of(context) + .size + .height; + final totalWidth = MediaQuery + .of(context) + .size + .width; + + return Container( + height: totalHeight, width: totalWidth, + color: Color(0xffd3faff), + child: Column(children: [ + SizedBox(height: totalHeight / 20,), + ListTile(title: Text("id"),leading: Text("name"),trailing: Text("password"),), + Container( + height: totalHeight-(totalHeight / 8), + child: ListView.builder( + itemCount: model2.allUsers.length, + itemBuilder: (context, index) { + if(model2.allUsers.isEmpty){ + return Container(); + } + final userr = model2.allUsers[index]; + user us = user( + name: userr.name, + id: userr.id, + password: userr.password + ); + return ListTile( + title: Text(us.id!), + leading: Text(us.name!), + trailing: Text(us.password!), + ); + } + ), + ) + ],), + ); + } +} \ No newline at end of file diff --git a/ecommerce/lib/manegerMainPage.dart b/ecommerce/lib/manegerMainPage.dart new file mode 100644 index 0000000..8e2b913 --- /dev/null +++ b/ecommerce/lib/manegerMainPage.dart @@ -0,0 +1,40 @@ + + +import 'package:ecommernce/manegerAllUsers.dart'; +import 'package:flutter/material.dart'; + +import 'manegerAllProducts.dart'; +import 'manegerAllProfits.dart'; + +class slManegerHome extends StatelessWidget{ + @override + Widget build(BuildContext context) { + final totalHeight=MediaQuery.of(context).size.height; + final totalWidth=MediaQuery.of(context).size.width; + return Container( + height: totalHeight,width: totalWidth, + color: Color(0xffd3faff), + child: Column(children: [ + SizedBox(height: totalHeight/4,), + ElevatedButton(onPressed: (){ + Navigator.push(context, MaterialPageRoute(builder: (context) { + return slManegerAllProducts(); + })); + }, child: Text("All Products")), + SizedBox(height: totalHeight/8,), + ElevatedButton(onPressed: (){ + Navigator.push(context, MaterialPageRoute(builder: (context) { + return slManegerAllUsers(); + })); + }, child: Text("All Users")), + SizedBox(height: totalHeight/8,), + ElevatedButton(onPressed: (){ + Navigator.push(context, MaterialPageRoute(builder: (context) { + return slManegerAllProfits(); + })); + }, child: Text("All Profits")), + + ],), + ); + } +} \ No newline at end of file diff --git a/ecommerce/lib/manegerProductAddOrEdit.dart b/ecommerce/lib/manegerProductAddOrEdit.dart new file mode 100644 index 0000000..eec3340 --- /dev/null +++ b/ecommerce/lib/manegerProductAddOrEdit.dart @@ -0,0 +1,193 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:ecommernce/model/product.dart'; +import 'package:flutter/material.dart'; + + +class slManegerProductDetalis extends StatelessWidget{ + int wh; + product? pro; + slManegerProductDetalis(this.wh,this.pro, {Key? key}):super (key: key); + @override + Widget build(BuildContext context) { + return sfManegerProductDetalis(wh,pro); + } +} + +class sfManegerProductDetalis extends StatefulWidget{ + int wh; + product? pro; + sfManegerProductDetalis(this.wh,this.pro, {Key? key}):super (key: key); + @override + State createState() { + return stateManegerProductDetalis(wh,pro); + } +} + +class stateManegerProductDetalis extends State{ + int wh; + product? pro; + stateManegerProductDetalis(this.wh,this.pro); + + final list=["jacket","boots","jeans","tshirt"]; + String? val; + + @override + void initState() { + super.initState(); + val=list[0]; + if(wh==1){ + name.text=pro!.name!; + cost.text=pro!.cost!; + val=pro!.type!; + discription.text=pro!.description!; + } + } + + @override + Widget build(BuildContext context) { + final totalHeight=MediaQuery.of(context).size.height; + final totalWidth=MediaQuery.of(context).size.width; + return Scaffold( + body: SingleChildScrollView( + child: Container( + height: totalHeight,width: totalWidth, + color: Color(0xffd3faff), + child: Column(children: [ + SizedBox(height: totalHeight/8,), + wh==1?toEdit(context):toAdd(context), + ],), + ), + ) + ); + } + TextEditingController name= TextEditingController(); + TextEditingController discription= TextEditingController(); + TextEditingController cost= TextEditingController(); + + Widget toAdd(BuildContext context){ + final totalHeight=MediaQuery.of(context).size.height; + final totalWidth=MediaQuery.of(context).size.width; + return Container( + child: Column(children: [ + Container( + color: Colors.red, + height: totalHeight/5,width: totalWidth/2, + ), + SizedBox(height: totalHeight/15,), + Container(child: Row(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("Type : "), + Container( + width: totalWidth/1.5,color:Colors.white,padding: EdgeInsets.symmetric(horizontal: totalWidth/30), + child: DropdownButtonHideUnderline( + child: DropdownButton( + isExpanded: true, + value: val, + items: list.map(buildmenu).toList(), + onChanged: (value){setState(() { + val = value as String?; + });}, + ), + ) + )],)), + SizedBox(height: totalHeight/40,), + Container(child: Row(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center,children: [Text("Name : "),Container(width: totalWidth/1.5,color:Colors.white,padding: EdgeInsets.symmetric(horizontal: totalWidth/30),child: TextField(controller: name,decoration: InputDecoration(border: InputBorder.none)))],)), + SizedBox(height: totalHeight/40,), + Container(child: Row(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center,children: [Text("Cost : "),Container(width: totalWidth/1.5,color:Colors.white,padding: EdgeInsets.symmetric(horizontal: totalWidth/30),child: TextField(controller: cost,decoration: InputDecoration(border: InputBorder.none)))],)), + SizedBox(height: totalHeight/40,), + Container(child: Row(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center,children: [Container(child: Text("Discription : ")),Container(height: totalHeight/4,width: totalWidth/1.7,color:Colors.white,padding: EdgeInsets.symmetric(horizontal: totalWidth/30),child: TextField(textInputAction: TextInputAction.newline,maxLines: 7,controller: discription,decoration: InputDecoration(border: InputBorder.none)))],)), + SizedBox(height: totalHeight/40,), + ElevatedButton(onPressed: () async{ + CollectionReference ref=FirebaseFirestore.instance.collection("products"); + ref.add({ + "name":name.text, + "cost":cost.text, + "description":discription.text, + "type":val, + "times":"0", + }); + final refId= await FirebaseFirestore.instance.collection("products").where("name",isEqualTo: name.text).get(); + final doc=refId.docs[0].id; + ref.doc(doc).set({ + "name":name.text, + "cost":cost.text, + "description":discription.text, + "type":val, + "times":"0", + "id":doc + }).then((value) { + Navigator.of(context).pop(); + }); + }, child: Text("Add")), + ], + ), + ); + } + + Widget toEdit(BuildContext context){ + final totalHeight=MediaQuery.of(context).size.height; + final totalWidth=MediaQuery.of(context).size.width; + return Container( + child: Column(children: [ + Container( + color: Colors.red, + height: totalHeight/5,width: totalWidth/2, + ), + SizedBox(height: totalHeight/15,), + Container(child: Row(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("Type : "), + Container( + width: totalWidth/1.5,color:Colors.white,padding: EdgeInsets.symmetric(horizontal: totalWidth/30), + child: DropdownButtonHideUnderline( + child: DropdownButton( + isExpanded: true, + value: val, + items: list.map(buildmenu).toList(), + onChanged: (value){setState(() { + val = value as String?; + });}, + ), + ) + )],)), + SizedBox(height: totalHeight/40,), + Container(child: Row(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center,children: [Text("Name : "),Container(width: totalWidth/1.5,color:Colors.white,padding: EdgeInsets.symmetric(horizontal: totalWidth/30),child: TextField(controller: name,decoration: InputDecoration(border: InputBorder.none)))],)), + SizedBox(height: totalHeight/40,), + Container(child: Row(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center,children: [Text("Cost : "),Container(width: totalWidth/1.5,color:Colors.white,padding: EdgeInsets.symmetric(horizontal: totalWidth/30),child: TextField(controller: cost,decoration: InputDecoration(border: InputBorder.none)))],)), + SizedBox(height: totalHeight/40,), + Container(child: Row(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center,children: [Container(child: Text("Discription : ")),Container(height: totalHeight/4,width: totalWidth/1.7,color:Colors.white,padding: EdgeInsets.symmetric(horizontal: totalWidth/30),child: TextField(controller: discription,decoration: InputDecoration(border: InputBorder.none)))],)), + SizedBox(height: totalHeight/40,), + Row( + crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton(onPressed: (){ + CollectionReference ref=FirebaseFirestore.instance.collection("products"); + ref.doc(pro!.id!).update({ + "name":name.text, + "cost":cost.text, + "description":discription.text, + "type":val, + }).then((_) { + // ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Edit Done"))); + }); + Navigator.of(context).pop(); + }, child: Text("Edit")), + SizedBox(width: totalWidth/5), + ElevatedButton(onPressed: (){ + CollectionReference ref=FirebaseFirestore.instance.collection("products"); + ref.doc(pro!.id!).delete().then((_) { + // ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Delete Done"))); + }); + Navigator.of(context).pop(); + }, child: Text("Delete")), + ], + ), + ], + ), + ); + } + + DropdownMenuItem buildmenu (String a){ + return DropdownMenuItem(value:a,child: Text(a)); + } +} \ No newline at end of file diff --git a/ecommerce/lib/model/product.dart b/ecommerce/lib/model/product.dart new file mode 100644 index 0000000..6ad91fc --- /dev/null +++ b/ecommerce/lib/model/product.dart @@ -0,0 +1,31 @@ +class product { + String? id; + String? name; + String? type; + String? cost; + String? description; + List? images; + String? times; + String? daytime; + String? daydate; + List? sizes; + List? colors; + List? reviews; + String? rating; + + product({ + this.id, + this.name, + this.type, + this.cost, + this.description, + this.images, + this.times, + this.daydate, + this.daytime, + this.colors, + this.sizes, + this.reviews, + this.rating, + }); +} diff --git a/ecommerce/lib/model/purchase.dart b/ecommerce/lib/model/purchase.dart new file mode 100644 index 0000000..3fe2cb9 --- /dev/null +++ b/ecommerce/lib/model/purchase.dart @@ -0,0 +1,11 @@ +import 'package:ecommernce/features/products/data/models/product_model.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:ecommernce/model/product.dart'; + +class purchase { + Product? p; + String? quantity; + Map? dtalis; + + purchase({this.dtalis, this.p, this.quantity}); +} diff --git a/ecommerce/lib/model/review.dart b/ecommerce/lib/model/review.dart new file mode 100644 index 0000000..706651b --- /dev/null +++ b/ecommerce/lib/model/review.dart @@ -0,0 +1,10 @@ +/*class review { + String? id; + String? name; + String? text; + String? date; + String? rating; + + review({this.id, this.name, this.text, this.date, this.rating}); +} +*/ \ No newline at end of file diff --git a/ecommerce/lib/model/user.dart b/ecommerce/lib/model/user.dart new file mode 100644 index 0000000..27cd5f1 --- /dev/null +++ b/ecommerce/lib/model/user.dart @@ -0,0 +1,10 @@ + + +class user { + String? id; + String? name; + String? password; + + user({this.id, this.name, this.password}); + +} \ No newline at end of file diff --git a/ecommerce/lib/modules/favorites/favoritePage.dart b/ecommerce/lib/modules/favorites/favoritePage.dart new file mode 100644 index 0000000..490a76f --- /dev/null +++ b/ecommerce/lib/modules/favorites/favoritePage.dart @@ -0,0 +1,57 @@ +import 'package:ecommernce/modules/favorites/favoriteWidget.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; + +/*class slFavoritePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return sfFavoritePage(); + } +} + +class sfFavoritePage extends StatefulWidget { + sfFavoritePage({Key? key}) : super(key: key); + @override + State createState() { + return stateFavoritePage(); + } +} + +class stateFavoritePage extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: Text("Favorites"), + ), + body: Container( + //height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + color: Color(0xffd3faff), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 40, + ), + Container( + height: MediaQuery.of(context).size.height - + AppBar().preferredSize.height - + 40 - + 34, + color: Color(0xffd3faff), + child: FirebaseAuth.instance.currentUser != null + ? favoriteListWidget(context) + : Center( + child: Text( + "You must to log in", + style: TextStyle(fontSize: 20), + ))) + ], + ), + ), + ); + } +} +*/ \ No newline at end of file diff --git a/ecommerce/lib/modules/favorites/favoriteProvider.dart b/ecommerce/lib/modules/favorites/favoriteProvider.dart new file mode 100644 index 0000000..a89ed92 --- /dev/null +++ b/ecommerce/lib/modules/favorites/favoriteProvider.dart @@ -0,0 +1,91 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:ecommernce/features/products/domain/entities/product.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class favoriteProvider extends ChangeNotifier { + List favorites = []; + + static favoriteProvider getWatch(BuildContext context) { + //print("watch"); + return context.watch(); + } + + static favoriteProvider getRead(BuildContext context) { + //print("read"); + return context.read(); + } + + /*Future> getFavorites(String id) async { + favorites.clear(); + CollectionReference ref = FirebaseFirestore.instance.collection("products"); + CollectionReference ref2 = FirebaseFirestore.instance + .collection("users") + .doc(id) + .collection("favorites"); + QuerySnapshot qsshid = await ref2.get(); // هان برجع كبشة documents + List listid = qsshid.docs; // وهان بنحطهم ك list + List ids = []; + listid.forEach((elementt) { + String id = elementt["id"]; + ids.add(id); + }); + ids.forEach((elemente) async { + QuerySnapshot qsshpro = await ref.where("id", isEqualTo: elemente).get(); + if (qsshpro.docs.isEmpty) { + QuerySnapshot qsshproo = + await ref2.where("id", isEqualTo: elemente).get(); + String id = qsshproo.docs[0]["fav id"]; + ref2.doc(id).delete(); + } else { + final element = qsshpro.docs[0]; + Product toAdd = Product( + name: element["name"], + id: element["id"], + type: element["type"], + times: element["times"], + cost: element["cost"], + images: element["images"], + description: element["description"], + sizes: element['sizes'], + colors: element['colors'], + rating: element['rating'], + ); + favorites.add(toAdd); + try { + notifyListeners(); + } catch (e) {} + } + }); + return favorites; + }*/ + + /*void refreshFavorites() { + favorites.clear(); + getFavorites(FirebaseAuth.instance.currentUser!.email!); + }*/ + + void removeFromFavorites(String id, int i, Product pro) { + CollectionReference ref = FirebaseFirestore.instance + .collection("users") + .doc(id) + .collection("favorites"); + ref.where("id", isEqualTo: pro.id!).get().then((value) { + QueryDocumentSnapshot qd = value.docs[0]; + ref.doc(qd.id).delete(); + }).then((value) { + favorites.removeAt(i); + notifyListeners(); + }); + } + + void removeFromFavoritesAsId(Product pro) { + favorites.removeWhere((element) => element.id == pro.id); + notifyListeners(); + } + + void addToFavorites(Product pro) { + favorites.add(pro); + notifyListeners(); + } +} diff --git a/ecommerce/lib/modules/favorites/favoriteWidget.dart b/ecommerce/lib/modules/favorites/favoriteWidget.dart new file mode 100644 index 0000000..9a10e6e --- /dev/null +++ b/ecommerce/lib/modules/favorites/favoriteWidget.dart @@ -0,0 +1,12 @@ + + +/*Widget favoriteListWidget(BuildContext context) { + return ListView.builder( + physics: BouncingScrollPhysics(), + itemCount: favoriteProvider.getWatch(context).favorites.length, + itemBuilder: (context, index) { + final pro = favoriteProvider.getWatch(context).favorites[index]; + return slOneProduct(pro); + }); +} +*/ \ No newline at end of file