├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── LaunchImageDark.png │ │ │ ├── LaunchImageDark@2x.png │ │ │ ├── LaunchImageDark@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-50x50@1x.png │ │ │ ├── Icon-App-50x50@2x.png │ │ │ ├── Icon-App-57x57@1x.png │ │ │ ├── Icon-App-57x57@2x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-72x72@1x.png │ │ │ ├── Icon-App-72x72@2x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchBackground.imageset │ │ │ ├── background.png │ │ │ ├── darkbackground.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ └── GoogleService-Info.plist ├── Runner.xcodeproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── firebase_app_id_file.json ├── RunnerTests │ └── RunnerTests.swift └── .gitignore ├── lib ├── core │ ├── helpers │ │ ├── enums.dart │ │ ├── debouncer.dart │ │ ├── cache_keys.dart │ │ ├── hive_boxes.dart │ │ ├── hive_keys.dart │ │ ├── app_regex.dart │ │ └── hive_type_ids.dart │ ├── api │ │ ├── api_result.dart │ │ ├── api_error_model.dart │ │ └── api_error_model.g.dart │ ├── utils │ │ ├── app_strings.dart │ │ ├── functions │ │ │ ├── check_if_onboarding_visited.dart │ │ │ ├── check_if_android_above_12.dart │ │ │ ├── toggle_lang.dart │ │ │ ├── check_if_user_is_logged_in.dart │ │ │ ├── get_color_from_string.dart │ │ │ ├── check_for_first_launch_and_device_theme.dart │ │ │ ├── circular_indicator_or_text_widget.dart │ │ │ └── execute_and_handle_errors.dart │ │ ├── bloc_observer.dart │ │ └── auto_route_observer.dart │ ├── widgets │ │ ├── products_grid_view_shimmer.dart │ │ ├── cancel_outlined_button.dart │ │ ├── custom_circular_progress_indicator.dart │ │ ├── stores_grid_view_shimmer.dart │ │ ├── horizontal_separated_list_view.dart │ │ ├── custom_cached_network_image.dart │ │ ├── email_text_form_field.dart │ │ └── username_text_form_field.dart │ ├── models │ │ ├── product_size.dart │ │ ├── sub_category.dart │ │ ├── product_color.dart │ │ ├── pagination.dart │ │ ├── store.dart │ │ └── storeify_user.dart │ └── themes │ │ └── app_colors.dart └── features │ ├── categories │ ├── data │ │ ├── models │ │ │ ├── fetch_sub_category_params.dart │ │ │ ├── fetch_sub_category_response.dart │ │ │ ├── fetch_categories_response.dart │ │ │ ├── fetch_sub_category_response.g.dart │ │ │ └── category.dart │ │ └── api │ │ │ └── categories_api_service.dart │ └── presentation │ │ ├── cubit │ │ ├── categories │ │ │ ├── categories_state.dart │ │ │ └── categories_cubit.dart │ │ └── sub_category │ │ │ └── sub_category_state.dart │ │ └── widgets │ │ ├── empty_sub_category_view.dart │ │ └── categories_sliver_shimmer_loading.dart │ ├── profile │ ├── data │ │ └── models │ │ │ ├── update_profile_params.dart │ │ │ ├── change_api_lang_params.dart │ │ │ ├── change_password_params.dart │ │ │ ├── change_api_lang_params.g.dart │ │ │ └── change_password_params.g.dart │ └── presentation │ │ ├── cubits │ │ ├── profile_state.dart │ │ ├── change_pass │ │ │ └── change_pass_state.dart │ │ └── update_profile │ │ │ └── update_profile_state.dart │ │ └── widgets │ │ ├── profile_settings_title.dart │ │ ├── dark_mode_switch_bloc_selector.dart │ │ ├── profile_view_sliver_app_bar.dart │ │ ├── profile_img.dart │ │ └── update_profile_form.dart │ ├── checkout │ ├── data │ │ └── models │ │ │ ├── payment_method.dart │ │ │ ├── fetch_city_data.dart │ │ │ ├── checkout_params.dart │ │ │ ├── fetch_city_data.g.dart │ │ │ ├── choose_payment_method_params.dart │ │ │ ├── choose_payment_method_params.g.dart │ │ │ ├── checkout_params.g.dart │ │ │ ├── checkout_response.dart │ │ │ └── checkout_response.g.dart │ └── presentation │ │ ├── widgets │ │ ├── check_circle.dart │ │ ├── custom_checkout_divider.dart │ │ ├── custom_progress_circle.dart │ │ ├── payment_method_process_progress.dart │ │ ├── container_contains_dot.dart │ │ ├── checkout_process_progress_dots.dart │ │ ├── how_do_u_want_to_pay_question.dart │ │ └── enable_location_error_widget.dart │ │ └── cubits │ │ └── payment_method │ │ └── payment_method_state.dart │ ├── layout │ ├── data │ │ └── models │ │ │ └── bottom_nav_item_attributes.dart │ └── presentation │ │ └── views │ │ └── layout_view.dart │ ├── onboarding │ ├── data │ │ └── models │ │ │ └── onboarding_attributes.dart │ └── presentation │ │ ├── cubit │ │ └── onboarding_state.dart │ │ └── widgets │ │ ├── custom_indicators.dart │ │ └── next_button_bloc_selector.dart │ ├── search │ ├── data │ │ ├── models │ │ │ ├── search_params.dart │ │ │ ├── search_params.g.dart │ │ │ ├── search_response.dart │ │ │ ├── search_response.g.dart │ │ │ └── fetch_search_data_response.dart │ │ ├── api │ │ │ └── search_api_service.dart │ │ └── datasource │ │ │ └── search_local_datasource.dart │ └── presentation │ │ └── cubit │ │ └── search_state.dart │ ├── auth │ ├── data │ │ ├── models │ │ │ ├── forgot_password_params.dart │ │ │ ├── validate_otp_params.dart │ │ │ ├── login_params.dart │ │ │ ├── reset_password_params.dart │ │ │ ├── login_params.g.dart │ │ │ ├── register_params.dart │ │ │ ├── forgot_password_params.g.dart │ │ │ ├── validate_otp_params.g.dart │ │ │ ├── reset_password_params.g.dart │ │ │ └── register_params.g.dart │ │ ├── api │ │ │ ├── validate_otp_api_service.dart │ │ │ ├── login_api_service.dart │ │ │ ├── reset_password_api_service.dart │ │ │ ├── forgot_password_api_service.dart │ │ │ └── register_api_service.dart │ │ ├── repos │ │ │ ├── validate_otp_repo.dart │ │ │ ├── login_repo.dart │ │ │ ├── register_repo.dart │ │ │ ├── reset_password_repo.dart │ │ │ └── forgot_password_repo.dart │ │ └── datasources │ │ │ └── auth_local_datasource.dart │ └── presentation │ │ ├── cubits │ │ ├── validate_otp │ │ │ └── validate_otp_state.dart │ │ ├── forgot_password │ │ │ └── forgot_password_state.dart │ │ ├── login │ │ │ └── login_state.dart │ │ ├── reset_password │ │ │ └── reset_password_state.dart │ │ └── register │ │ │ └── register_state.dart │ │ ├── widgets │ │ ├── sign_up_text_button.dart │ │ ├── text_field_label.dart │ │ └── forgot_password │ │ │ └── forgot_password_form.dart │ │ └── views │ │ ├── login_view.dart │ │ ├── register_view.dart │ │ └── verification_view.dart │ ├── cart │ ├── presentation │ │ ├── widgets │ │ │ ├── cart_summary_divider.dart │ │ │ ├── cart_sliver_shimmer_loading.dart │ │ │ ├── cart_loading_view.dart │ │ │ ├── empty_cart_widget.dart │ │ │ ├── summary_info.dart │ │ │ └── control_cart_product_quantity.dart │ │ └── cubit │ │ │ └── cart_state.dart │ └── data │ │ ├── models │ │ ├── add_product_to_cart_params.dart │ │ ├── fetch_cart_response.dart │ │ ├── add_product_to_cart_params.g.dart │ │ ├── cart.dart │ │ ├── fetch_cart_response.g.dart │ │ └── cart.g.dart │ │ └── api │ │ └── cart_api_service.dart │ ├── home │ ├── data │ │ ├── api │ │ │ └── home_api_service.dart │ │ ├── models │ │ │ └── fetch_home_response.dart │ │ ├── datasources │ │ │ └── home_local_datasource.dart │ │ └── repos │ │ │ └── home_repo.dart │ └── presentation │ │ └── widgets │ │ └── list_title.dart │ ├── favorites │ ├── data │ │ └── models │ │ │ ├── prefer_params.dart │ │ │ ├── prefer_params.g.dart │ │ │ ├── fetch_fav_stores_response.dart │ │ │ └── fetch_favorite_products_response.dart │ └── presentation │ │ ├── widgets │ │ └── favorite_products_grid_view.dart │ │ └── cubits │ │ ├── fetch_favorites │ │ └── fetch_favorites_state.dart │ │ └── favorites │ │ └── general_state.dart │ ├── payment │ ├── data │ │ ├── models │ │ │ ├── card_type.dart │ │ │ └── payment_card_details.dart │ │ ├── api │ │ │ └── payment_api_service.dart │ │ ├── repositories │ │ │ └── payment_repo.dart │ │ └── datasource │ │ │ └── payment_local_datasource.dart │ └── presentation │ │ ├── widgets │ │ ├── payment_text_field_label.dart │ │ ├── payment_progress_circles.dart │ │ ├── card_details_text.dart │ │ └── check_box_bloc_selector.dart │ │ └── cubits │ │ └── payment_state.dart │ ├── product_details │ └── presentation │ │ ├── widgets │ │ └── product_details_section_title.dart │ │ └── cubit │ │ └── product_details_state.dart │ └── stores │ ├── data │ └── models │ │ ├── fetch_store_categories_response.dart │ │ ├── fetch_stores_response.dart │ │ ├── fetch_store_offers_response.dart │ │ └── fetch_store_branches.dart │ └── presentation │ ├── cubits │ ├── stores │ │ └── stores_state.dart │ └── store_details │ │ └── store_details_state.dart │ └── widgets │ ├── categories_grid_view_shimmer.dart │ └── stores_shimmer_loading.dart ├── assets ├── app_icon.png ├── icons │ ├── Search.png │ ├── profile.png │ └── location_icon.png ├── images │ ├── cash.png │ ├── visa.png │ ├── paypal.png │ ├── splash.png │ ├── empty-cart.png │ ├── credit_card.png │ ├── dark_splash.png │ ├── master_card.png │ ├── no_internet.png │ ├── on_boarding1.png │ ├── on_boarding2.png │ ├── on_boarding3.png │ ├── default_error.png │ ├── empty-favorites.png │ ├── no-notifications.png │ ├── otp_verification.png │ ├── splash_android_12.png │ ├── payment_successfully.png │ └── dark_splash_android_12.png └── fonts │ ├── Poppins │ ├── Poppins-Bold.ttf │ ├── Poppins-Medium.ttf │ ├── Poppins-Regular.ttf │ ├── Poppins-ExtraBold.ttf │ └── Poppins-SemiBold.ttf │ └── PottaOne │ └── PottaOne-Regular.ttf ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── drawable │ │ │ │ │ ├── background.png │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-hdpi │ │ │ │ │ ├── splash.png │ │ │ │ │ └── android12splash.png │ │ │ │ ├── drawable-mdpi │ │ │ │ │ ├── splash.png │ │ │ │ │ └── android12splash.png │ │ │ │ ├── drawable-xhdpi │ │ │ │ │ ├── splash.png │ │ │ │ │ └── android12splash.png │ │ │ │ ├── drawable-v21 │ │ │ │ │ ├── background.png │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-xxhdpi │ │ │ │ │ ├── splash.png │ │ │ │ │ └── android12splash.png │ │ │ │ ├── drawable-xxxhdpi │ │ │ │ │ ├── splash.png │ │ │ │ │ └── android12splash.png │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable-night-hdpi │ │ │ │ │ ├── splash.png │ │ │ │ │ └── android12splash.png │ │ │ │ ├── drawable-night-mdpi │ │ │ │ │ ├── splash.png │ │ │ │ │ └── android12splash.png │ │ │ │ ├── drawable-night │ │ │ │ │ ├── background.png │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable-night-v21 │ │ │ │ │ ├── background.png │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-night-xhdpi │ │ │ │ │ ├── splash.png │ │ │ │ │ └── android12splash.png │ │ │ │ ├── drawable-night-xxhdpi │ │ │ │ │ ├── splash.png │ │ │ │ │ └── android12splash.png │ │ │ │ ├── drawable-night-xxxhdpi │ │ │ │ │ ├── splash.png │ │ │ │ │ └── android12splash.png │ │ │ │ ├── values-v31 │ │ │ │ │ └── styles.xml │ │ │ │ ├── values-night-v31 │ │ │ │ │ └── styles.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ └── kotlin │ │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── store_ify │ │ │ │ └── MainActivity.kt │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── google-services.json ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── build.gradle └── settings.gradle ├── devtools_options.yaml ├── analysis_options.yaml ├── flutter_native_splash.yaml ├── .gitignore └── LICENSE.txt /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /lib/core/helpers/enums.dart: -------------------------------------------------------------------------------- 1 | enum FavItemType { product, store } 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /assets/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/app_icon.png -------------------------------------------------------------------------------- /assets/icons/Search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/icons/Search.png -------------------------------------------------------------------------------- /assets/images/cash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/cash.png -------------------------------------------------------------------------------- /assets/images/visa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/visa.png -------------------------------------------------------------------------------- /assets/icons/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/icons/profile.png -------------------------------------------------------------------------------- /assets/images/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/paypal.png -------------------------------------------------------------------------------- /assets/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/splash.png -------------------------------------------------------------------------------- /assets/images/empty-cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/empty-cart.png -------------------------------------------------------------------------------- /assets/icons/location_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/icons/location_icon.png -------------------------------------------------------------------------------- /assets/images/credit_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/credit_card.png -------------------------------------------------------------------------------- /assets/images/dark_splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/dark_splash.png -------------------------------------------------------------------------------- /assets/images/master_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/master_card.png -------------------------------------------------------------------------------- /assets/images/no_internet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/no_internet.png -------------------------------------------------------------------------------- /assets/images/on_boarding1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/on_boarding1.png -------------------------------------------------------------------------------- /assets/images/on_boarding2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/on_boarding2.png -------------------------------------------------------------------------------- /assets/images/on_boarding3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/on_boarding3.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /assets/images/default_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/default_error.png -------------------------------------------------------------------------------- /assets/images/empty-favorites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/empty-favorites.png -------------------------------------------------------------------------------- /assets/images/no-notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/no-notifications.png -------------------------------------------------------------------------------- /assets/images/otp_verification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/otp_verification.png -------------------------------------------------------------------------------- /assets/images/splash_android_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/splash_android_12.png -------------------------------------------------------------------------------- /assets/fonts/Poppins/Poppins-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/fonts/Poppins/Poppins-Bold.ttf -------------------------------------------------------------------------------- /assets/images/payment_successfully.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/payment_successfully.png -------------------------------------------------------------------------------- /assets/fonts/Poppins/Poppins-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/fonts/Poppins/Poppins-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins/Poppins-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/fonts/Poppins/Poppins-Regular.ttf -------------------------------------------------------------------------------- /assets/images/dark_splash_android_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/images/dark_splash_android_12.png -------------------------------------------------------------------------------- /assets/fonts/Poppins/Poppins-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/fonts/Poppins/Poppins-ExtraBold.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins/Poppins-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/fonts/Poppins/Poppins-SemiBold.ttf -------------------------------------------------------------------------------- /assets/fonts/PottaOne/PottaOne-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/assets/fonts/PottaOne/PottaOne-Regular.ttf -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-hdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-mdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-xhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-xxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night-hdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night-mdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-hdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-mdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night-xhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night-xxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-xhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-xxhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-xxxhdpi/android12splash.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-hdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night-hdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-mdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night-mdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night-xhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png -------------------------------------------------------------------------------- /devtools_options.yaml: -------------------------------------------------------------------------------- 1 | description: This file stores settings for Dart & Flutter DevTools. 2 | documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedghaly15/Storeify/HEAD/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/store_ify/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.store_ify 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip 6 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | analyzer: 4 | exclude: 5 | - "**/*.g.dart" 6 | - "**/*.freezed.dart" 7 | errors: 8 | invalid_annotation_target: ignore 9 | use_build_context_synchronously: ignore 10 | -------------------------------------------------------------------------------- /lib/features/categories/data/models/fetch_sub_category_params.dart: -------------------------------------------------------------------------------- 1 | class FetchSubCategoryParams { 2 | final int categoryId; 3 | final int subCategoryId; 4 | 5 | const FetchSubCategoryParams({ 6 | required this.categoryId, 7 | required this.subCategoryId, 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /lib/features/profile/data/models/update_profile_params.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | class UpdateProfileParams { 4 | final String? username, email; 5 | final File? img; 6 | 7 | const UpdateProfileParams({ 8 | this.username, 9 | this.email, 10 | this.img, 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/firebase_app_id_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "file_generated_by": "FlutterFire CLI", 3 | "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", 4 | "GOOGLE_APP_ID": "1:74739450491:ios:bd1f70b20eb2a84e8e58de", 5 | "FIREBASE_PROJECT_ID": "store-ify-ecommerce", 6 | "GCM_SENDER_ID": "74739450491" 7 | } -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /lib/core/helpers/debouncer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | class Debouncer { 6 | final Duration duration; 7 | Timer? _timer; 8 | 9 | Debouncer({required this.duration}); 10 | 11 | void run(VoidCallback action) { 12 | _timer?.cancel(); 13 | _timer = Timer(duration, action); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /lib/features/checkout/data/models/payment_method.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'payment_method.freezed.dart'; 4 | 5 | @freezed 6 | class PaymentMethod with _$PaymentMethod { 7 | const factory PaymentMethod({ 8 | required int id, 9 | required String name, 10 | required String image, 11 | }) = _PaymentMethod; 12 | } 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/core/api/api_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/core/api/api_error_model.dart'; 3 | 4 | part 'api_result.freezed.dart'; 5 | 6 | @Freezed() 7 | abstract class ApiResult with _$ApiResult { 8 | const factory ApiResult.success(T data) = Success; 9 | const factory ApiResult.error(ApiErrorModel errorModel) = Error; 10 | } 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = '../build' 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(':app') 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/features/layout/data/models/bottom_nav_item_attributes.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BottomNavItemAttributes { 4 | const BottomNavItemAttributes({ 5 | required this.index, 6 | required this.icon, 7 | required this.labelKey, 8 | required this.color, 9 | }); 10 | 11 | final int index; 12 | final IconData icon; 13 | final String labelKey; 14 | final Color color; 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/onboarding/data/models/onboarding_attributes.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'onboarding_attributes.freezed.dart'; 4 | 5 | @freezed 6 | class OnboardingAttributes with _$OnboardingAttributes { 7 | const factory OnboardingAttributes({ 8 | required String image, 9 | required String titleKey, 10 | required String subTitleKey, 11 | }) = _OnboardingAttributes; 12 | } 13 | -------------------------------------------------------------------------------- /flutter_native_splash.yaml: -------------------------------------------------------------------------------- 1 | flutter_native_splash: 2 | # IOS & Android below 12 3 | color: "#ffffff" 4 | image: assets/images/splash.png 5 | image_dark: assets/images/dark_splash.png 6 | color_dark: "#000000" 7 | 8 | android_12: 9 | image: assets/images/splash_android_12.png 10 | color: "#ffffff" 11 | image_dark: assets/images/dark_splash_android_12.png 12 | color_dark: "#000000" 13 | 14 | android: true 15 | ios: true -------------------------------------------------------------------------------- /lib/features/search/data/models/search_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'search_params.g.dart'; 4 | 5 | @JsonSerializable() 6 | class SearchParams { 7 | final String search; 8 | 9 | const SearchParams(this.search); 10 | 11 | factory SearchParams.fromJson(Map json) => 12 | _$SearchParamsFromJson(json); 13 | Map toJson() => _$SearchParamsToJson(this); 14 | } 15 | -------------------------------------------------------------------------------- /lib/core/api/api_error_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'api_error_model.g.dart'; 4 | part 'api_error_model.freezed.dart'; 5 | 6 | @freezed 7 | class ApiErrorModel with _$ApiErrorModel { 8 | const factory ApiErrorModel({ 9 | @JsonKey(name: 'code') String? error, 10 | }) = _ApiErrorModel; 11 | 12 | factory ApiErrorModel.fromJson(Map json) => 13 | _$ApiErrorModelFromJson(json); 14 | } 15 | -------------------------------------------------------------------------------- /lib/core/helpers/cache_keys.dart: -------------------------------------------------------------------------------- 1 | class CacheKeys { 2 | CacheKeys._(); 3 | 4 | static const String locale = 'locale'; 5 | static const String onboarding = 'onboarding'; 6 | static const String storeifyUser = 'storeifyUser'; 7 | static const String appTheme = 'appTheme'; 8 | static const String firstLaunch = 'firstLaunch'; 9 | static const String countryCodeTimestamp = 'countryCodeTimestamp'; 10 | static const String countryCode = 'countryCode'; 11 | } 12 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/core/utils/app_strings.dart: -------------------------------------------------------------------------------- 1 | class AppStrings { 2 | static const String appTitle = 'Store-ify'; 3 | static const String fontFamily = 'Poppins'; 4 | static const String pottaOneFont = 'PottaOne'; 5 | static const String localePath = 'assets/translations'; 6 | static const String arabicLangCode = 'ar'; 7 | static const String englishLangCode = 'en'; 8 | static const String searchRequiredErrorKey = 'SEARCH_REQUIRED'; 9 | static const String checkoutDateFormat = 'yyyy-MM-dd'; 10 | } 11 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "background.png", 5 | "idiom" : "universal" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "filename" : "darkbackground.png", 15 | "idiom" : "universal" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/features/checkout/data/models/fetch_city_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'fetch_city_data.g.dart'; 4 | 5 | @JsonSerializable() 6 | class FetchCityData { 7 | @JsonKey(name: 'display_name') 8 | final String displayName; 9 | 10 | FetchCityData({required this.displayName}); 11 | 12 | factory FetchCityData.fromJson(Map json) => 13 | _$FetchCityDataFromJson(json); 14 | Map toJson() => _$FetchCityDataToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/profile/data/models/change_api_lang_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'change_api_lang_params.g.dart'; 4 | 5 | @JsonSerializable() 6 | class ChangeApiLangParams { 7 | final String lang; 8 | 9 | const ChangeApiLangParams({required this.lang}); 10 | 11 | factory ChangeApiLangParams.fromJson(Map json) => 12 | _$ChangeApiLangParamsFromJson(json); 13 | 14 | Map toJson() => _$ChangeApiLangParamsToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /lib/core/utils/functions/check_if_onboarding_visited.dart: -------------------------------------------------------------------------------- 1 | import 'package:store_ify/core/helpers/shared_pref_helper.dart'; 2 | import 'package:store_ify/core/helpers/cache_keys.dart'; 3 | import 'package:store_ify/core/utils/app_constants.dart'; 4 | 5 | Future checkIfOnboardingIsVisited() async { 6 | final onboarding = await SharedPrefHelper.getBool(CacheKeys.onboarding); 7 | if (onboarding != null) { 8 | isOnboardingVisited = onboarding; 9 | } else { 10 | isOnboardingVisited = false; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/features/auth/data/models/forgot_password_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'forgot_password_params.g.dart'; 4 | 5 | @JsonSerializable() 6 | class ForgotPasswordParams { 7 | final String email; 8 | 9 | const ForgotPasswordParams({required this.email}); 10 | 11 | factory ForgotPasswordParams.fromJson(Map json) => 12 | _$ForgotPasswordParamsFromJson(json); 13 | 14 | Map toJson() => _$ForgotPasswordParamsToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/auth/data/models/validate_otp_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'validate_otp_params.g.dart'; 4 | 5 | @JsonSerializable() 6 | class ValidateOtpParams { 7 | final String otp, email; 8 | 9 | const ValidateOtpParams({required this.otp, required this.email}); 10 | 11 | factory ValidateOtpParams.fromJson(Map json) => 12 | _$ValidateOtpParamsFromJson(json); 13 | 14 | Map toJson() => _$ValidateOtpParamsToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/auth/data/models/login_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'login_params.g.dart'; 4 | 5 | @JsonSerializable() 6 | class LoginParams { 7 | final String email; 8 | final String password; 9 | 10 | const LoginParams({ 11 | required this.email, 12 | required this.password, 13 | }); 14 | 15 | factory LoginParams.fromJson(Map json) => 16 | _$LoginParamsFromJson(json); 17 | 18 | Map toJson() => _$LoginParamsToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/cart/presentation/widgets/cart_summary_divider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/themes/app_colors.dart'; 4 | 5 | class CartSummaryDivider extends StatelessWidget { 6 | const CartSummaryDivider({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Divider( 11 | color: AppColors.colorBEBEC3, 12 | thickness: 0.5.w, 13 | height: 1.h, 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/features/home/data/api/home_api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart'; 3 | import 'package:store_ify/core/api/end_points.dart'; 4 | import 'package:store_ify/features/home/data/models/fetch_home_response.dart'; 5 | 6 | part 'home_api_service.g.dart'; 7 | 8 | @RestApi(baseUrl: EndPoints.baseUrl) 9 | abstract class HomeApiService { 10 | factory HomeApiService(Dio dio, {String baseUrl}) = _HomeApiService; 11 | 12 | @GET(EndPoints.fetchHomeData) 13 | Future fetchHomeData(); 14 | } 15 | -------------------------------------------------------------------------------- /lib/features/favorites/data/models/prefer_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'prefer_params.g.dart'; 4 | 5 | @JsonSerializable() 6 | class PreferParams { 7 | @JsonKey(name: 'product_id') 8 | final int? productId; 9 | @JsonKey(name: 'store_id') 10 | final int? storeId; 11 | 12 | const PreferParams({this.productId, this.storeId}); 13 | 14 | factory PreferParams.fromJson(Map json) => 15 | _$PreferParamsFromJson(json); 16 | Map toJson() => _$PreferParamsToJson(this); 17 | } 18 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/cubits/validate_otp/validate_otp_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'validate_otp_state.freezed.dart'; 4 | 5 | @freezed 6 | class ValidateOtpState with _$ValidateOtpState { 7 | const factory ValidateOtpState.initial() = _Initial; 8 | const factory ValidateOtpState.validateOtpLoading() = ValidateOtpLoading; 9 | const factory ValidateOtpState.validateOtpSuccess() = ValidateOtpSuccess; 10 | const factory ValidateOtpState.validateOtpError(String error) = 11 | ValidateOtpError; 12 | } 13 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/core/utils/functions/check_if_android_above_12.dart: -------------------------------------------------------------------------------- 1 | import 'package:device_info_plus/device_info_plus.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:store_ify/core/di/dependency_injection.dart'; 4 | import 'package:store_ify/core/utils/app_constants.dart'; 5 | 6 | Future checkIfAndroidAbove12() async { 7 | final androidInfo = await getIt.get().androidInfo; 8 | debugPrint( 9 | '*#*#*#*#*#* ANDROID VERSION: ${androidInfo.version.release} *#*#*#*#*#*'); 10 | isAndroidAbove12 = 11 | int.parse(androidInfo.version.release) >= 12 ? true : false; 12 | } 13 | -------------------------------------------------------------------------------- /lib/features/onboarding/presentation/cubit/onboarding_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'onboarding_state.freezed.dart'; 4 | 5 | enum OnboardingStateStatus { 6 | initial, 7 | onPageChanged, 8 | } 9 | 10 | @freezed 11 | class OnboardingState with _$OnboardingState { 12 | const factory OnboardingState({ 13 | required OnboardingStateStatus status, 14 | @Default(false) bool isLastPage, 15 | }) = _OnboardingState; 16 | 17 | factory OnboardingState.initial() => const OnboardingState( 18 | status: OnboardingStateStatus.initial, 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/search/data/models/search_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'search_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | SearchParams _$SearchParamsFromJson(Map json) => SearchParams( 10 | json['search'] as String, 11 | ); 12 | 13 | Map _$SearchParamsToJson(SearchParams instance) => 14 | { 15 | 'search': instance.search, 16 | }; 17 | -------------------------------------------------------------------------------- /lib/core/widgets/products_grid_view_shimmer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/core/utils/app_constants.dart'; 3 | import 'package:store_ify/core/widgets/shimmer_widget.dart'; 4 | 5 | class ProductsGridViewShimmer extends StatelessWidget { 6 | const ProductsGridViewShimmer({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return GridView.builder( 11 | gridDelegate: AppConstants.favProductsGridDelegate, 12 | padding: AppConstants.categoryPadding, 13 | itemCount: 10, 14 | itemBuilder: (_, __) => const ShimmerWidget(), 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/cubits/forgot_password/forgot_password_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'forgot_password_state.freezed.dart'; 4 | 5 | @freezed 6 | class ForgotPasswordState with _$ForgotPasswordState { 7 | const factory ForgotPasswordState.initial() = _Initial; 8 | const factory ForgotPasswordState.forgotPasswordLoading() = 9 | ForgotPasswordLoading; 10 | const factory ForgotPasswordState.forgotPasswordSuccess() = 11 | ForgotPasswordSuccess; 12 | const factory ForgotPasswordState.forgotPasswordError(String error) = 13 | ForgotPasswordError; 14 | } 15 | -------------------------------------------------------------------------------- /lib/core/api/api_error_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'api_error_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$ApiErrorModelImpl _$$ApiErrorModelImplFromJson(Map json) => 10 | _$ApiErrorModelImpl( 11 | error: json['code'] as String?, 12 | ); 13 | 14 | Map _$$ApiErrorModelImplToJson(_$ApiErrorModelImpl instance) => 15 | { 16 | 'code': instance.error, 17 | }; 18 | -------------------------------------------------------------------------------- /lib/features/checkout/data/models/checkout_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'checkout_params.g.dart'; 4 | 5 | @JsonSerializable() 6 | class CheckoutParams { 7 | final String username, address, phone, date, time; 8 | 9 | const CheckoutParams({ 10 | required this.username, 11 | required this.address, 12 | required this.phone, 13 | required this.date, 14 | required this.time, 15 | }); 16 | 17 | factory CheckoutParams.fromJson(Map json) => 18 | _$CheckoutParamsFromJson(json); 19 | 20 | Map toJson() => _$CheckoutParamsToJson(this); 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/checkout/data/models/fetch_city_data.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'fetch_city_data.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | FetchCityData _$FetchCityDataFromJson(Map json) => 10 | FetchCityData( 11 | displayName: json['display_name'] as String, 12 | ); 13 | 14 | Map _$FetchCityDataToJson(FetchCityData instance) => 15 | { 16 | 'display_name': instance.displayName, 17 | }; 18 | -------------------------------------------------------------------------------- /lib/core/models/product_size.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hive_flutter/hive_flutter.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | 5 | part 'product_size.freezed.dart'; 6 | part 'product_size.g.dart'; 7 | 8 | @HiveType(typeId: HiveTypeIds.productSize) 9 | @freezed 10 | class ProductSize with _$ProductSize { 11 | @JsonSerializable() 12 | const factory ProductSize({ 13 | @HiveField(0) required int id, 14 | @HiveField(1) required String size, 15 | }) = _ProductSize; 16 | 17 | factory ProductSize.fromJson(Map json) => 18 | _$ProductSizeFromJson(json); 19 | } 20 | -------------------------------------------------------------------------------- /lib/core/models/sub_category.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hive_flutter/hive_flutter.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | 5 | part 'sub_category.g.dart'; 6 | part 'sub_category.freezed.dart'; 7 | 8 | @HiveType(typeId: HiveTypeIds.subCategory) 9 | @freezed 10 | class SubCategory with _$SubCategory { 11 | @JsonSerializable() 12 | const factory SubCategory({ 13 | @HiveField(0) required int id, 14 | @HiveField(1) required String name, 15 | }) = _SubCategory; 16 | 17 | factory SubCategory.fromJson(Map json) => 18 | _$SubCategoryFromJson(json); 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/payment/data/models/card_type.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hive_flutter/hive_flutter.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | 5 | part 'card_type.freezed.dart'; 6 | part 'card_type.g.dart'; 7 | 8 | @HiveType(typeId: HiveTypeIds.cardType) 9 | @freezed 10 | class CardType with _$CardType { 11 | @JsonSerializable() 12 | const factory CardType({ 13 | @HiveField(0) required String image, 14 | @HiveField(1) required String nameKey, 15 | }) = _CardType; 16 | 17 | factory CardType.fromJson(Map json) => 18 | _$$CardTypeImplFromJson(json); 19 | } 20 | -------------------------------------------------------------------------------- /lib/core/models/product_color.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hive_flutter/hive_flutter.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | 5 | part 'product_color.freezed.dart'; 6 | part 'product_color.g.dart'; 7 | 8 | @HiveType(typeId: HiveTypeIds.productColor) 9 | @freezed 10 | class ProductColor with _$ProductColor { 11 | @JsonSerializable() 12 | const factory ProductColor({ 13 | @HiveField(0) required int id, 14 | @HiveField(1) required String color, 15 | }) = _ProductColor; 16 | 17 | factory ProductColor.fromJson(Map json) => 18 | _$ProductColorFromJson(json); 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/profile/data/models/change_password_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'change_password_params.g.dart'; 4 | 5 | @JsonSerializable(fieldRename: FieldRename.snake) 6 | class ChangePasswordParams { 7 | final String currentPassword, password, passwordConfirmation; 8 | 9 | ChangePasswordParams({ 10 | required this.currentPassword, 11 | required this.password, 12 | required this.passwordConfirmation, 13 | }); 14 | 15 | factory ChangePasswordParams.fromJson(Map json) => 16 | _$ChangePasswordParamsFromJson(json); 17 | 18 | Map toJson() => _$ChangePasswordParamsToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/search/data/models/search_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:store_ify/core/models/pagination.dart'; 3 | import 'package:store_ify/core/models/product.dart'; 4 | 5 | part 'search_response.g.dart'; 6 | 7 | @JsonSerializable() 8 | class SearchResponse { 9 | final List products; 10 | final Pagination? pagination; 11 | 12 | const SearchResponse({ 13 | required this.products, 14 | required this.pagination, 15 | }); 16 | 17 | factory SearchResponse.fromJson(Map json) => 18 | _$SearchResponseFromJson(json); 19 | Map toJson() => _$SearchResponseToJson(this); 20 | } 21 | -------------------------------------------------------------------------------- /lib/core/utils/functions/toggle_lang.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:store_ify/core/utils/app_strings.dart'; 5 | import 'package:store_ify/features/profile/presentation/cubits/profile_cubit.dart'; 6 | 7 | void toggleLang(BuildContext context) { 8 | final newLocale = context.locale.languageCode == AppStrings.englishLangCode 9 | ? const Locale(AppStrings.arabicLangCode) 10 | : const Locale(AppStrings.englishLangCode); 11 | 12 | context.setLocale(newLocale); 13 | context.read().toggleLocale(newLocale.languageCode); 14 | } 15 | -------------------------------------------------------------------------------- /lib/core/widgets/cancel_outlined_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:store_ify/core/widgets/main_button.dart'; 4 | import 'package:store_ify/generated/locale_keys.g.dart'; 5 | 6 | class CancelOutlinedButton extends StatelessWidget { 7 | const CancelOutlinedButton({super.key, this.onCancel}); 8 | 9 | final VoidCallback? onCancel; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return MainButton( 14 | onPressed: onCancel ?? () => context.maybePop(), 15 | textKey: LocaleKeys.cancel, 16 | isOutlined: true, 17 | margin: EdgeInsets.zero, 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/checkout/data/models/choose_payment_method_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'choose_payment_method_params.g.dart'; 4 | 5 | @JsonSerializable() 6 | class ChoosePaymentMethodParams { 7 | final int paymentId; 8 | @JsonKey(name: 'payment_method') 9 | final String paymentMethod; 10 | 11 | const ChoosePaymentMethodParams({ 12 | required this.paymentId, 13 | required this.paymentMethod, 14 | }); 15 | 16 | factory ChoosePaymentMethodParams.fromJson(Map json) => 17 | _$ChoosePaymentMethodParamsFromJson(json); 18 | 19 | Map toJson() => _$ChoosePaymentMethodParamsToJson(this); 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/profile/data/models/change_api_lang_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'change_api_lang_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ChangeApiLangParams _$ChangeApiLangParamsFromJson(Map json) => 10 | ChangeApiLangParams( 11 | lang: json['lang'] as String, 12 | ); 13 | 14 | Map _$ChangeApiLangParamsToJson( 15 | ChangeApiLangParams instance) => 16 | { 17 | 'lang': instance.lang, 18 | }; 19 | -------------------------------------------------------------------------------- /lib/features/auth/data/models/reset_password_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'reset_password_params.g.dart'; 4 | 5 | @JsonSerializable() 6 | class ResetPasswordParams { 7 | final String email, password; 8 | @JsonKey(name: 'password_confirmation') 9 | final String passwordConfirmation; 10 | 11 | const ResetPasswordParams({ 12 | required this.email, 13 | required this.password, 14 | required this.passwordConfirmation, 15 | }); 16 | 17 | factory ResetPasswordParams.fromJson(Map json) => 18 | _$ResetPasswordParamsFromJson(json); 19 | Map toJson() => _$ResetPasswordParamsToJson(this); 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/auth/data/models/login_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'login_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | LoginParams _$LoginParamsFromJson(Map json) => LoginParams( 10 | email: json['email'] as String, 11 | password: json['password'] as String, 12 | ); 13 | 14 | Map _$LoginParamsToJson(LoginParams instance) => 15 | { 16 | 'email': instance.email, 17 | 'password': instance.password, 18 | }; 19 | -------------------------------------------------------------------------------- /lib/features/payment/data/api/payment_api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart'; 3 | import 'package:store_ify/core/api/end_points.dart'; 4 | import 'package:store_ify/features/payment/data/models/payment_card_details.dart'; 5 | 6 | part 'payment_api_service.g.dart'; 7 | 8 | @RestApi(baseUrl: EndPoints.baseUrl) 9 | abstract class PaymentApiService { 10 | factory PaymentApiService(Dio dio, {String baseUrl}) = _PaymentApiService; 11 | 12 | @POST('${EndPoints.pay}{orderId}') 13 | Future orderPay( 14 | @Path('orderId') int orderId, 15 | @Body() PaymentCardDetails params, [ 16 | @CancelRequest() CancelToken? cancelToken, 17 | ]); 18 | } 19 | -------------------------------------------------------------------------------- /lib/features/auth/data/models/register_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'register_params.g.dart'; 4 | 5 | @JsonSerializable() 6 | class RegisterParams { 7 | final String username, email, password; 8 | @JsonKey(name: 'password_confirmation') 9 | final String passwordConfirmation; 10 | 11 | const RegisterParams({ 12 | required this.username, 13 | required this.email, 14 | required this.password, 15 | required this.passwordConfirmation, 16 | }); 17 | 18 | factory RegisterParams.fromJson(Map json) => 19 | _$RegisterParamsFromJson(json); 20 | 21 | Map toJson() => _$RegisterParamsToJson(this); 22 | } 23 | -------------------------------------------------------------------------------- /lib/features/auth/data/models/forgot_password_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'forgot_password_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ForgotPasswordParams _$ForgotPasswordParamsFromJson( 10 | Map json) => 11 | ForgotPasswordParams( 12 | email: json['email'] as String, 13 | ); 14 | 15 | Map _$ForgotPasswordParamsToJson( 16 | ForgotPasswordParams instance) => 17 | { 18 | 'email': instance.email, 19 | }; 20 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /lib/features/auth/data/models/validate_otp_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'validate_otp_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ValidateOtpParams _$ValidateOtpParamsFromJson(Map json) => 10 | ValidateOtpParams( 11 | otp: json['otp'] as String, 12 | email: json['email'] as String, 13 | ); 14 | 15 | Map _$ValidateOtpParamsToJson(ValidateOtpParams instance) => 16 | { 17 | 'otp': instance.otp, 18 | 'email': instance.email, 19 | }; 20 | -------------------------------------------------------------------------------- /lib/core/utils/functions/check_if_user_is_logged_in.dart: -------------------------------------------------------------------------------- 1 | import 'package:store_ify/core/helpers/extensions.dart'; 2 | import 'package:store_ify/core/helpers/secure_storage_helper.dart'; 3 | import 'package:store_ify/core/helpers/cache_keys.dart'; 4 | import 'package:store_ify/core/utils/app_constants.dart'; 5 | import 'package:store_ify/features/auth/data/datasources/auth_local_datasource.dart'; 6 | 7 | Future checkIfUserIsLoggedIn() async { 8 | final cachedUser = 9 | await SecureStorageHelper.getSecuredString(CacheKeys.storeifyUser); 10 | if (cachedUser.isNullOrEmpty) { 11 | isUserLoggedIn = false; 12 | } else { 13 | isUserLoggedIn = true; 14 | currentUser = await AuthLocalDatasource.getCachedUser(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/core/utils/functions/get_color_from_string.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | Color? getColorFromString(String colorName) { 4 | final Map colorMap = { 5 | 'red': Colors.red, 6 | 'blue': Colors.blue, 7 | 'green': Colors.green, 8 | 'yellow': Colors.yellow, 9 | 'orange': Colors.orange, 10 | 'purple': Colors.purple, 11 | 'pink': Colors.pink, 12 | 'brown': Colors.brown, 13 | 'grey': Colors.grey, 14 | 'black': Colors.black, 15 | 'white': Colors.white, 16 | 'cyan': Colors.cyan, 17 | 'amber': Colors.amber, 18 | 'indigo': Colors.indigo, 19 | 'lime': Colors.lime, 20 | 'teal': Colors.teal, 21 | }; 22 | 23 | return colorMap[colorName.toLowerCase()]; 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/widgets/check_circle.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/themes/app_colors.dart'; 4 | 5 | class CheckCircle extends StatelessWidget { 6 | const CheckCircle({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Container( 11 | height: 20.48.h, 12 | width: 20.48.h, 13 | decoration: const BoxDecoration( 14 | shape: BoxShape.circle, 15 | color: AppColors.primaryColor, 16 | ), 17 | child: Icon( 18 | Icons.check, 19 | color: AppColors.lightModeColor, 20 | size: 16.w, 21 | ), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/favorites/data/models/prefer_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'prefer_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | PreferParams _$PreferParamsFromJson(Map json) => PreferParams( 10 | productId: (json['product_id'] as num?)?.toInt(), 11 | storeId: (json['store_id'] as num?)?.toInt(), 12 | ); 13 | 14 | Map _$PreferParamsToJson(PreferParams instance) => 15 | { 16 | 'product_id': instance.productId, 17 | 'store_id': instance.storeId, 18 | }; 19 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/cubits/login/login_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/core/models/storeify_user.dart'; 3 | 4 | part 'login_state.freezed.dart'; 5 | 6 | enum LoginStateStatus { 7 | initial, 8 | loginLoading, 9 | loginSuccess, 10 | loginError, 11 | togglePassVisibility, 12 | } 13 | 14 | @freezed 15 | class LoginState with _$LoginState { 16 | const factory LoginState({ 17 | required LoginStateStatus status, 18 | StoreifyUser? user, 19 | String? error, 20 | @Default(true) bool isPasswordObscure, 21 | }) = _LoginState; 22 | 23 | factory LoginState.initial() => const LoginState( 24 | status: LoginStateStatus.initial, 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/product_details/presentation/widgets/product_details_section_title.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:store_ify/core/themes/app_colors.dart'; 4 | import 'package:store_ify/core/themes/app_text_styles.dart'; 5 | 6 | class ProductDetailsSectionTitle extends StatelessWidget { 7 | const ProductDetailsSectionTitle({ 8 | super.key, 9 | required this.titleKey, 10 | }); 11 | 12 | final String titleKey; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Text( 17 | context.tr(titleKey), 18 | style: AppTextStyles.textStyle16Medium 19 | .copyWith(color: AppColors.primaryColor), 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/features/cart/data/models/add_product_to_cart_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'add_product_to_cart_params.g.dart'; 4 | 5 | @JsonSerializable() 6 | class AddProductToCartParams { 7 | final int productId; 8 | @JsonKey(name: 'color_id') 9 | final int? colorId; 10 | @JsonKey(name: 'size_id') 11 | final int? sizeId; 12 | final int quantity; 13 | 14 | const AddProductToCartParams({ 15 | required this.productId, 16 | required this.quantity, 17 | this.sizeId, 18 | this.colorId, 19 | }); 20 | 21 | factory AddProductToCartParams.fromJson(Map json) => 22 | _$AddProductToCartParamsFromJson(json); 23 | Map toJson() => _$AddProductToCartParamsToJson(this); 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/payment/presentation/widgets/payment_text_field_label.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/themes/app_text_styles.dart'; 4 | import 'package:store_ify/features/auth/presentation/widgets/text_field_label.dart'; 5 | 6 | class PaymentTextFieldLabel extends StatelessWidget { 7 | const PaymentTextFieldLabel({ 8 | super.key, 9 | required this.labelKey, 10 | }); 11 | 12 | final String labelKey; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return TextFieldLabel( 17 | labelKey: labelKey, 18 | margin: EdgeInsetsDirectional.only(bottom: 11.h), 19 | textStyle: AppTextStyles.textStyle14Regular, 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/features/favorites/data/models/fetch_fav_stores_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/hive_flutter.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | import 'package:store_ify/core/models/store.dart'; 5 | 6 | part 'fetch_fav_stores_response.g.dart'; 7 | 8 | @HiveType(typeId: HiveTypeIds.fetchFavStoresResponse) 9 | @JsonSerializable() 10 | class FetchFavStoresResponse { 11 | @HiveField(0) 12 | final List stores; 13 | 14 | const FetchFavStoresResponse({required this.stores}); 15 | 16 | factory FetchFavStoresResponse.fromJson(Map json) => 17 | _$FetchFavStoresResponseFromJson(json); 18 | Map toJson() => _$FetchFavStoresResponseToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/auth/data/api/validate_otp_api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart'; 3 | import 'package:retrofit/retrofit.dart' as retrofit; 4 | import 'package:store_ify/core/api/end_points.dart'; 5 | import 'package:store_ify/features/auth/data/models/validate_otp_params.dart'; 6 | 7 | part 'validate_otp_api_service.g.dart'; 8 | 9 | @RestApi(baseUrl: EndPoints.baseUrl) 10 | abstract class ValidateOtpApiService { 11 | factory ValidateOtpApiService(Dio dio, {String baseUrl}) = 12 | _ValidateOtpApiService; 13 | 14 | @POST(EndPoints.validateOtp) 15 | @retrofit.Headers({'Accept-Language': 'en'}) 16 | Future validateOtp( 17 | @Body() ValidateOtpParams params, [ 18 | @CancelRequest() CancelToken? cancelToken, 19 | ]); 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/auth/data/api/login_api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart' as retrofit; 3 | import 'package:retrofit/retrofit.dart'; 4 | 5 | import 'package:store_ify/core/api/end_points.dart'; 6 | import 'package:store_ify/core/models/storeify_user.dart'; 7 | import 'package:store_ify/features/auth/data/models/login_params.dart'; 8 | 9 | part 'login_api_service.g.dart'; 10 | 11 | @RestApi(baseUrl: EndPoints.baseUrl) 12 | abstract class LoginApiService { 13 | factory LoginApiService(Dio dio, {String baseUrl}) = _LoginApiService; 14 | 15 | @POST(EndPoints.login) 16 | @retrofit.Headers({'Accept-Language': 'en'}) 17 | Future login( 18 | @Body() LoginParams params, [ 19 | @CancelRequest() CancelToken? cancelToken, 20 | ]); 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/cart/presentation/widgets/cart_sliver_shimmer_loading.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/utils/app_constants.dart'; 4 | import 'package:store_ify/core/widgets/shimmer_widget.dart'; 5 | 6 | class CartSliverShimmerLoading extends StatelessWidget { 7 | const CartSliverShimmerLoading({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return SliverList.builder( 12 | itemCount: 6, 13 | itemBuilder: (_, __) => ShimmerWidget( 14 | margin: AppConstants.cartItemMargin, 15 | constraints: BoxConstraints( 16 | maxHeight: 110.h, 17 | maxWidth: double.infinity, 18 | ), 19 | ), 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/widgets/custom_checkout_divider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/themes/app_colors.dart'; 4 | 5 | class CustomCheckoutDivider extends StatelessWidget { 6 | const CustomCheckoutDivider({ 7 | super.key, 8 | this.color = AppColors.primaryColor, 9 | }); 10 | 11 | final Color color; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Container( 16 | height: 2.h, 17 | width: 25.87.w, 18 | margin: EdgeInsets.symmetric(horizontal: 4.w), 19 | decoration: BoxDecoration( 20 | borderRadius: BorderRadius.all(Radius.circular(2.16.r)), 21 | color: color, 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/auth/data/api/reset_password_api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart'; 3 | import 'package:retrofit/retrofit.dart' as retrofit; 4 | import 'package:store_ify/core/api/end_points.dart'; 5 | import 'package:store_ify/features/auth/data/models/reset_password_params.dart'; 6 | 7 | part 'reset_password_api_service.g.dart'; 8 | 9 | @RestApi(baseUrl: EndPoints.baseUrl) 10 | abstract class ResetPasswordApiService { 11 | factory ResetPasswordApiService(Dio dio, {String baseUrl}) = 12 | _ResetPasswordApiService; 13 | 14 | @POST(EndPoints.resetPassword) 15 | @retrofit.Headers({'Accept-Language': 'en'}) 16 | Future resetPassword( 17 | @Body() ResetPasswordParams params, [ 18 | @CancelRequest() CancelToken? cancelToken, 19 | ]); 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/auth/data/repos/validate_otp_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:store_ify/core/api/api_result.dart'; 3 | import 'package:store_ify/core/utils/functions/execute_and_handle_errors.dart'; 4 | import 'package:store_ify/features/auth/data/api/validate_otp_api_service.dart'; 5 | import 'package:store_ify/features/auth/data/models/validate_otp_params.dart'; 6 | 7 | class ValidateOtpRepo { 8 | final ValidateOtpApiService _validateOtpApiService; 9 | 10 | ValidateOtpRepo(this._validateOtpApiService); 11 | 12 | Future> validateOtp( 13 | ValidateOtpParams params, [ 14 | CancelToken? cancelToken, 15 | ]) { 16 | return executeAndHandleErrors( 17 | () async => await _validateOtpApiService.validateOtp(params, cancelToken), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "74739450491", 4 | "project_id": "store-ify-ecommerce", 5 | "storage_bucket": "store-ify-ecommerce.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:74739450491:android:0a91c6343db878cb8e58de", 11 | "android_client_info": { 12 | "package_name": "com.example.store_ify" 13 | } 14 | }, 15 | "oauth_client": [], 16 | "api_key": [ 17 | { 18 | "current_key": "AIzaSyA1RcgQdie4CIh6UMl1fH1Ze5VFk8uP6jI" 19 | } 20 | ], 21 | "services": { 22 | "appinvite_service": { 23 | "other_platform_oauth_client": [] 24 | } 25 | } 26 | } 27 | ], 28 | "configuration_version": "1" 29 | } -------------------------------------------------------------------------------- /lib/features/auth/data/api/forgot_password_api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart'; 3 | import 'package:retrofit/retrofit.dart' as retrofit; 4 | import 'package:store_ify/core/api/end_points.dart'; 5 | import 'package:store_ify/features/auth/data/models/forgot_password_params.dart'; 6 | 7 | part 'forgot_password_api_service.g.dart'; 8 | 9 | @RestApi(baseUrl: EndPoints.baseUrl) 10 | abstract class ForgotPasswordApiService { 11 | factory ForgotPasswordApiService(Dio dio, {String baseUrl}) = 12 | _ForgotPasswordApiService; 13 | 14 | @POST(EndPoints.forgotPassword) 15 | @retrofit.Headers({'Accept-Language': 'en'}) 16 | Future forgotPassword( 17 | @Body() ForgotPasswordParams params, [ 18 | @CancelRequest() CancelToken? cancelToken, 19 | ]); 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/auth/data/repos/login_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:store_ify/core/api/api_result.dart'; 3 | import 'package:store_ify/core/models/storeify_user.dart'; 4 | import 'package:store_ify/core/utils/functions/execute_and_handle_errors.dart'; 5 | import 'package:store_ify/features/auth/data/api/login_api_service.dart'; 6 | import 'package:store_ify/features/auth/data/models/login_params.dart'; 7 | 8 | class LoginRepo { 9 | final LoginApiService _loginApiService; 10 | 11 | LoginRepo(this._loginApiService); 12 | 13 | Future> login( 14 | LoginParams params, [ 15 | CancelToken? cancelToken, 16 | ]) { 17 | return executeAndHandleErrors( 18 | () async => await _loginApiService.login(params, cancelToken), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/cart/data/models/fetch_cart_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:store_ify/features/cart/data/models/cart.dart'; 3 | 4 | part 'fetch_cart_response.g.dart'; 5 | 6 | @JsonSerializable(explicitToJson: true) 7 | class FetchCartResponse { 8 | final List cart; 9 | final int totalItems, delivery; 10 | final double totalPrice, subTotalPrice; 11 | 12 | const FetchCartResponse({ 13 | required this.cart, 14 | required this.totalItems, 15 | required this.totalPrice, 16 | required this.subTotalPrice, 17 | required this.delivery, 18 | }); 19 | 20 | factory FetchCartResponse.fromJson(Map json) => 21 | _$FetchCartResponseFromJson(json); 22 | Map toJson() => _$FetchCartResponseToJson(this); 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/categories/presentation/cubit/categories/categories_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/features/categories/data/models/fetch_categories_response.dart'; 3 | 4 | part 'categories_state.freezed.dart'; 5 | 6 | enum CategoriesStateStatus { 7 | initial, 8 | fetchCategoriesLoading, 9 | fetchCategoriesSuccess, 10 | fetchCategoriesError, 11 | } 12 | 13 | @freezed 14 | class CategoriesState with _$CategoriesState { 15 | const factory CategoriesState({ 16 | required CategoriesStateStatus status, 17 | FetchCategoriesResponse? categoriesResponse, 18 | String? error, 19 | }) = _CategoriesState; 20 | 21 | factory CategoriesState.initial() => const CategoriesState( 22 | status: CategoriesStateStatus.initial, 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/auth/data/api/register_api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart' as retrofit; 3 | import 'package:retrofit/retrofit.dart'; 4 | 5 | import 'package:store_ify/core/api/end_points.dart'; 6 | import 'package:store_ify/core/models/storeify_user.dart'; 7 | import 'package:store_ify/features/auth/data/models/register_params.dart'; 8 | 9 | part 'register_api_service.g.dart'; 10 | 11 | @RestApi(baseUrl: EndPoints.baseUrl) 12 | abstract class RegisterApiService { 13 | factory RegisterApiService(Dio dio, {String baseUrl}) = _RegisterApiService; 14 | 15 | @POST(EndPoints.register) 16 | @retrofit.Headers({'Accept-Language': 'en'}) 17 | Future register( 18 | @Body() RegisterParams params, [ 19 | @CancelRequest() CancelToken? cancelToken, 20 | ]); 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/cubits/reset_password/reset_password_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'reset_password_state.freezed.dart'; 4 | 5 | enum ResetPassStateStatus { 6 | initial, 7 | resetPassLoading, 8 | resetPassSuccess, 9 | resetPassError, 10 | togglePassVisibility, 11 | toggleConfirmPassVisibility, 12 | } 13 | 14 | @freezed 15 | class ResetPasswordState with _$ResetPasswordState { 16 | const factory ResetPasswordState({ 17 | required ResetPassStateStatus status, 18 | String? error, 19 | @Default(true) bool isPassObscure, 20 | @Default(true) bool isConfirmPassObscure, 21 | }) = _ResetPasswordState; 22 | 23 | factory ResetPasswordState.initial() => const ResetPasswordState( 24 | status: ResetPassStateStatus.initial, 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "7.3.0" apply false 22 | id "org.jetbrains.kotlin.android" version "1.9.20" apply false 23 | } 24 | 25 | include ":app" -------------------------------------------------------------------------------- /lib/core/themes/app_colors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppColors { 4 | static const Color primaryColor = Color(0xFFFE431A); 5 | static const Color lightModeColor = Colors.white; 6 | static const Color subTitleColor = Color(0xFF575757); 7 | static const Color blueColor = Color(0xFF0F3557); 8 | static const Color greyColor = Color(0xffD0CFCE); 9 | static const Color discountColor = Color(0xff3E3D3B); 10 | static const Color fontPrimaryColor = Color(0xff0B2841); 11 | static const Color color2A94F4 = Color(0xff2A94F4); 12 | static const Color colorBEBEC3 = Color(0xffBEBEC3); 13 | static const Color colorD9D9D9 = Color(0xffD9D9D9); 14 | static const Color colorF6F6F6 = Color(0xffF6F6F6); 15 | static const Color darkColor = Colors.black; 16 | static Color? secondaryDarkColor = Colors.grey[900]; 17 | } 18 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/widgets/sign_up_text_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:easy_localization/easy_localization.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:store_ify/core/router/app_router.dart'; 5 | import 'package:store_ify/core/themes/app_text_styles.dart'; 6 | import 'package:store_ify/generated/locale_keys.g.dart'; 7 | 8 | class SignUpTextButton extends StatelessWidget { 9 | const SignUpTextButton({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return TextButton( 14 | style: TextButton.styleFrom( 15 | textStyle: AppTextStyles.textStyle16Regular, 16 | ), 17 | onPressed: () => context.pushRoute(const RegisterRoute()), 18 | child: Text(context.tr(LocaleKeys.signUp)), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/home/presentation/widgets/list_title.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:easy_localization/easy_localization.dart'; 4 | import 'package:store_ify/core/themes/app_text_styles.dart'; 5 | 6 | class ListTitle extends StatelessWidget { 7 | const ListTitle({ 8 | super.key, 9 | required this.titleKey, 10 | this.bottomPadding = 0, 11 | }); 12 | 13 | final String titleKey; 14 | final double bottomPadding; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Container( 19 | margin: EdgeInsetsDirectional.only(bottom: bottomPadding.h, start: 16.w), 20 | child: Text( 21 | context.tr(titleKey), 22 | style: AppTextStyles.textStyle16Regular, 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/favorites/data/models/fetch_favorite_products_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/hive_flutter.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | import 'package:store_ify/core/models/product.dart'; 5 | 6 | part 'fetch_favorite_products_response.g.dart'; 7 | 8 | @HiveType(typeId: HiveTypeIds.fetchFavoriteProductsResponse) 9 | @JsonSerializable() 10 | class FetchFavoriteProductsResponse { 11 | @HiveField(0) 12 | final List products; 13 | 14 | const FetchFavoriteProductsResponse({required this.products}); 15 | 16 | factory FetchFavoriteProductsResponse.fromJson(Map json) => 17 | _$FetchFavoriteProductsResponseFromJson(json); 18 | Map toJson() => _$FetchFavoriteProductsResponseToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/auth/data/repos/register_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:store_ify/core/api/api_result.dart'; 3 | import 'package:store_ify/core/models/storeify_user.dart'; 4 | import 'package:store_ify/core/utils/functions/execute_and_handle_errors.dart'; 5 | import 'package:store_ify/features/auth/data/api/register_api_service.dart'; 6 | import 'package:store_ify/features/auth/data/models/register_params.dart'; 7 | 8 | class RegisterRepo { 9 | final RegisterApiService _registerApiService; 10 | 11 | RegisterRepo(this._registerApiService); 12 | 13 | Future> register( 14 | RegisterParams params, [ 15 | CancelToken? cancelToken, 16 | ]) { 17 | return executeAndHandleErrors( 18 | () async => await _registerApiService.register(params, cancelToken), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/layout/presentation/views/layout_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:store_ify/core/router/app_router.dart'; 4 | import 'package:store_ify/features/layout/presentation/widgets/custom_bottom_nav_bar.dart'; 5 | 6 | @RoutePage() 7 | class LayoutView extends StatelessWidget { 8 | const LayoutView({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return AutoTabsScaffold( 13 | routes: const [ 14 | HomeRouteBody(), 15 | StoresRoute(), 16 | CartRoute(), 17 | FavoritesRoute() 18 | ], 19 | bottomNavigationBuilder: (_, tabsRouter) => CustomBottomNavBar( 20 | currentIndex: tabsRouter.activeIndex, 21 | onTap: tabsRouter.setActiveIndex, 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/core/utils/functions/check_for_first_launch_and_device_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:store_ify/core/helpers/shared_pref_helper.dart'; 3 | import 'package:store_ify/core/helpers/cache_keys.dart'; 4 | import 'package:store_ify/core/utils/app_constants.dart'; 5 | 6 | Future checkForFirstLaunchAndDeviceTheme() async { 7 | final firstLaunch = await SharedPrefHelper.getBool(CacheKeys.firstLaunch); 8 | if (firstLaunch == null) { 9 | isFirstLaunch = true; 10 | await SharedPrefHelper.setData(CacheKeys.firstLaunch, true); 11 | _checkTheDeviceTheme(); 12 | } else { 13 | isFirstLaunch = false; 14 | } 15 | } 16 | 17 | void _checkTheDeviceTheme() { 18 | final brightness = PlatformDispatcher.instance.platformBrightness; 19 | isDeviceDarkModeActive = brightness == Brightness.dark ? true : false; 20 | } 21 | -------------------------------------------------------------------------------- /lib/core/helpers/hive_boxes.dart: -------------------------------------------------------------------------------- 1 | class HiveBoxes { 2 | HiveBoxes._(); 3 | 4 | static const String homeResponseBox = 'homeResponseBox'; 5 | static const String categoriesResponseBox = 'categoriesResponseBox'; 6 | static const String favProductsBox = 'favProductsBox'; 7 | static const String favStoresBox = 'favStoresBox'; 8 | static const String fetchStoresBox = 'fetchStoresBox'; 9 | static const String fetchCategoryStoresBox = 'fetchCategoryStoresBox'; 10 | static const String subCategoryBox = 'fetchSubCategoryBox'; 11 | static const String fetchStoreBranchesBox = 'fetchStoreBranchesBox'; 12 | static const String fetchStoreCategoriesBox = 'fetchStoreCategoriesBox'; 13 | static const String fetchStoreOffersBox = 'fetchStoreOffersBox'; 14 | static const String searchDataBox = 'searchDataBox'; 15 | static const String paymentBox = 'paymentBox'; 16 | } 17 | -------------------------------------------------------------------------------- /lib/features/auth/data/repos/reset_password_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:store_ify/core/api/api_result.dart'; 3 | import 'package:store_ify/core/utils/functions/execute_and_handle_errors.dart'; 4 | import 'package:store_ify/features/auth/data/api/reset_password_api_service.dart'; 5 | import 'package:store_ify/features/auth/data/models/reset_password_params.dart'; 6 | 7 | class ResetPasswordRepo { 8 | final ResetPasswordApiService _resetPasswordApiService; 9 | 10 | ResetPasswordRepo(this._resetPasswordApiService); 11 | 12 | Future> resetPassword( 13 | ResetPasswordParams params, [ 14 | CancelToken? cancelToken, 15 | ]) { 16 | return executeAndHandleErrors( 17 | () async => await _resetPasswordApiService.resetPassword( 18 | params, 19 | cancelToken, 20 | ), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/cubits/register/register_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/core/models/storeify_user.dart'; 3 | 4 | part 'register_state.freezed.dart'; 5 | 6 | enum RegisterStateStatus { 7 | initial, 8 | registerLoading, 9 | registerSuccess, 10 | registerError, 11 | togglePassVisibility, 12 | toggleConfirmPassVisibility, 13 | } 14 | 15 | @freezed 16 | class RegisterState with _$RegisterState { 17 | const factory RegisterState({ 18 | required RegisterStateStatus status, 19 | StoreifyUser? user, 20 | String? error, 21 | @Default(true) bool isPassObscure, 22 | @Default(true) bool isConfirmPassObscure, 23 | }) = _RegisterState; 24 | 25 | factory RegisterState.initial() => const RegisterState( 26 | status: RegisterStateStatus.initial, 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /lib/features/checkout/data/models/choose_payment_method_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'choose_payment_method_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ChoosePaymentMethodParams _$ChoosePaymentMethodParamsFromJson( 10 | Map json) => 11 | ChoosePaymentMethodParams( 12 | paymentId: (json['paymentId'] as num).toInt(), 13 | paymentMethod: json['payment_method'] as String, 14 | ); 15 | 16 | Map _$ChoosePaymentMethodParamsToJson( 17 | ChoosePaymentMethodParams instance) => 18 | { 19 | 'paymentId': instance.paymentId, 20 | 'payment_method': instance.paymentMethod, 21 | }; 22 | -------------------------------------------------------------------------------- /lib/features/payment/presentation/widgets/payment_progress_circles.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/features/checkout/presentation/widgets/check_circle.dart'; 3 | import 'package:store_ify/features/checkout/presentation/widgets/custom_checkout_divider.dart'; 4 | import 'package:store_ify/features/checkout/presentation/widgets/custom_progress_circle.dart'; 5 | 6 | class PaymentProgressCircles extends StatelessWidget { 7 | const PaymentProgressCircles({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return const Row( 12 | mainAxisAlignment: MainAxisAlignment.center, 13 | children: [ 14 | CustomProgressCircle(), 15 | CustomCheckoutDivider(), 16 | CustomProgressCircle(), 17 | CustomCheckoutDivider(), 18 | CheckCircle(), 19 | ], 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/core/widgets/custom_circular_progress_indicator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/themes/app_colors.dart'; 4 | 5 | class CustomCircularProgressIndicator extends StatelessWidget { 6 | const CustomCircularProgressIndicator({ 7 | super.key, 8 | this.color = AppColors.primaryColor, 9 | this.strokeWidth = 4, 10 | this.backgroundColor, 11 | }); 12 | 13 | final Color color; 14 | final Color? backgroundColor; 15 | final double strokeWidth; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return CircularProgressIndicator.adaptive( 20 | valueColor: AlwaysStoppedAnimation(color), 21 | strokeCap: StrokeCap.butt, 22 | strokeWidth: strokeWidth.w, 23 | backgroundColor: backgroundColor, 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/auth/data/repos/forgot_password_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:store_ify/core/api/api_result.dart'; 3 | import 'package:store_ify/core/utils/functions/execute_and_handle_errors.dart'; 4 | import 'package:store_ify/features/auth/data/api/forgot_password_api_service.dart'; 5 | import 'package:store_ify/features/auth/data/models/forgot_password_params.dart'; 6 | 7 | class ForgotPasswordRepo { 8 | final ForgotPasswordApiService _forgotPasswordApiService; 9 | 10 | ForgotPasswordRepo(this._forgotPasswordApiService); 11 | 12 | Future> forgotPassword( 13 | ForgotPasswordParams params, [ 14 | CancelToken? cancelToken, 15 | ]) { 16 | return executeAndHandleErrors( 17 | () async => await _forgotPasswordApiService.forgotPassword( 18 | params, 19 | cancelToken, 20 | ), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/stores/data/models/fetch_store_categories_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hive_flutter/hive_flutter.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | import 'package:store_ify/features/categories/data/models/category.dart'; 5 | 6 | part 'fetch_store_categories_response.g.dart'; 7 | 8 | @HiveType(typeId: HiveTypeIds.fetchStoreCategoriesResponse) 9 | @JsonSerializable(explicitToJson: true) 10 | class FetchStoreCategoriesResponse { 11 | @HiveField(0) 12 | final List categories; 13 | 14 | const FetchStoreCategoriesResponse({required this.categories}); 15 | 16 | factory FetchStoreCategoriesResponse.fromJson(Map json) => 17 | _$FetchStoreCategoriesResponseFromJson(json); 18 | Map toJson() => _$FetchStoreCategoriesResponseToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/cubits/profile_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/core/utils/app_strings.dart'; 3 | 4 | part 'profile_state.freezed.dart'; 5 | 6 | enum ProfileStateStatus { 7 | initial, 8 | logoutLoading, 9 | logoutSuccess, 10 | logoutError, 11 | deleteAccountLoading, 12 | deleteAccountSuccess, 13 | deleteAccountError, 14 | changeLocaleLocally, 15 | changeApiLangSuccess, 16 | changeApiLangError, 17 | } 18 | 19 | @freezed 20 | sealed class ProfileState with _$ProfileState { 21 | const factory ProfileState({ 22 | required ProfileStateStatus status, 23 | @Default(AppStrings.englishLangCode) String langCode, 24 | String? error, 25 | }) = _ProfileState; 26 | 27 | factory ProfileState.initial() => const ProfileState( 28 | status: ProfileStateStatus.initial, 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/profile_settings_title.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:easy_localization/easy_localization.dart'; 4 | import 'package:store_ify/core/themes/app_colors.dart'; 5 | import 'package:store_ify/core/themes/app_text_styles.dart'; 6 | 7 | class ProfileSettingsTitle extends StatelessWidget { 8 | const ProfileSettingsTitle({super.key, required this.titleKey}); 9 | 10 | final String titleKey; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Container( 15 | margin: EdgeInsetsDirectional.only(bottom: 6.h, start: 22.w), 16 | child: Text( 17 | context.tr(titleKey), 18 | style: AppTextStyles.textStyle16Medium.copyWith( 19 | color: AppColors.primaryColor, 20 | ), 21 | ), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/features/auth/data/models/reset_password_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'reset_password_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ResetPasswordParams _$ResetPasswordParamsFromJson(Map json) => 10 | ResetPasswordParams( 11 | email: json['email'] as String, 12 | password: json['password'] as String, 13 | passwordConfirmation: json['password_confirmation'] as String, 14 | ); 15 | 16 | Map _$ResetPasswordParamsToJson( 17 | ResetPasswordParams instance) => 18 | { 19 | 'email': instance.email, 20 | 'password': instance.password, 21 | 'password_confirmation': instance.passwordConfirmation, 22 | }; 23 | -------------------------------------------------------------------------------- /lib/features/categories/data/models/fetch_sub_category_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/core/models/pagination.dart'; 3 | import 'package:store_ify/core/models/product.dart'; 4 | import 'package:store_ify/core/models/sub_category.dart'; 5 | 6 | part 'fetch_sub_category_response.g.dart'; 7 | 8 | @JsonSerializable(explicitToJson: true) 9 | class FetchSubCategoryResponse { 10 | final SubCategory category; 11 | final List products; 12 | final Pagination pagination; 13 | 14 | const FetchSubCategoryResponse({ 15 | required this.category, 16 | required this.products, 17 | required this.pagination, 18 | }); 19 | 20 | factory FetchSubCategoryResponse.fromJson(Map json) => 21 | _$FetchSubCategoryResponseFromJson(json); 22 | Map toJson() => _$FetchSubCategoryResponseToJson(this); 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/payment/data/repositories/payment_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:store_ify/core/api/api_result.dart'; 3 | import 'package:store_ify/core/utils/functions/execute_and_handle_errors.dart'; 4 | import 'package:store_ify/features/payment/data/api/payment_api_service.dart'; 5 | import 'package:store_ify/features/payment/data/models/payment_card_details.dart'; 6 | 7 | class PaymentRepo { 8 | final PaymentApiService _paymentApiService; 9 | 10 | const PaymentRepo(this._paymentApiService); 11 | 12 | Future> pay({ 13 | required int orderId, 14 | required PaymentCardDetails paymentCardDetails, 15 | CancelToken? cancelToken, 16 | }) { 17 | return executeAndHandleErrors( 18 | () async => await _paymentApiService.orderPay( 19 | orderId, 20 | paymentCardDetails, 21 | cancelToken, 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/cubits/change_pass/change_pass_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'change_pass_state.freezed.dart'; 4 | 5 | enum ChangePassStateStatus { 6 | initial, 7 | changePasswordLoading, 8 | changePasswordSuccess, 9 | changePasswordError, 10 | toggleOldPassVisibility, 11 | toggleNewPassVisibility, 12 | toggleConfirmNewPassVisibility, 13 | } 14 | 15 | @freezed 16 | class ChangePassState with _$ChangePassState { 17 | const factory ChangePassState({ 18 | required ChangePassStateStatus status, 19 | String? error, 20 | @Default(true) bool oldPasswordObscured, 21 | @Default(true) bool newPasswordObscured, 22 | @Default(true) bool confirmNewPassObscured, 23 | }) = _ChangePassState; 24 | 25 | factory ChangePassState.initial() => const ChangePassState( 26 | status: ChangePassStateStatus.initial, 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/views/login_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:store_ify/core/di/dependency_injection.dart'; 5 | import 'package:store_ify/features/auth/presentation/cubits/login/login_cubit.dart'; 6 | import 'package:store_ify/features/auth/presentation/widgets/login/login_view_body.dart'; 7 | 8 | @RoutePage() 9 | class LoginView extends StatelessWidget implements AutoRouteWrapper { 10 | const LoginView({super.key}); 11 | 12 | @override 13 | Widget wrappedRoute(BuildContext context) { 14 | return BlocProvider( 15 | create: (_) => getIt.get(), 16 | child: this, 17 | ); 18 | } 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return const Scaffold( 23 | body: LoginViewBody(), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/search/presentation/cubit/search_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/features/search/data/models/fetch_search_data_response.dart'; 3 | import 'package:store_ify/features/search/data/models/search_response.dart'; 4 | 5 | part 'search_state.freezed.dart'; 6 | 7 | enum SearchStateStatus { 8 | initial, 9 | searchLoading, 10 | searchSuccess, 11 | searchError, 12 | fetchSearchDataLoading, 13 | fetchSearchDataSuccess, 14 | fetchSearchDataError, 15 | } 16 | 17 | @freezed 18 | class SearchState with _$SearchState { 19 | const factory SearchState({ 20 | required SearchStateStatus status, 21 | SearchResponse? searchResult, 22 | FetchSearchDataResponse? searchData, 23 | String? error, 24 | }) = _SearchState; 25 | 26 | factory SearchState.initial() => const SearchState( 27 | status: SearchStateStatus.initial, 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /lib/features/stores/data/models/fetch_stores_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/hive_flutter.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | import 'package:store_ify/core/models/pagination.dart'; 5 | import 'package:store_ify/core/models/store.dart'; 6 | 7 | part 'fetch_stores_response.g.dart'; 8 | 9 | @HiveType(typeId: HiveTypeIds.fetchStores) 10 | @JsonSerializable(explicitToJson: true) 11 | class FetchStoresResponse { 12 | @HiveField(0) 13 | final List stores; 14 | @HiveField(1) 15 | final Pagination pagination; 16 | 17 | const FetchStoresResponse({ 18 | required this.stores, 19 | required this.pagination, 20 | }); 21 | 22 | factory FetchStoresResponse.fromJson(Map json) => 23 | _$FetchStoresResponseFromJson(json); 24 | Map toJson() => _$FetchStoresResponseToJson(this); 25 | } 26 | -------------------------------------------------------------------------------- /lib/core/widgets/stores_grid_view_shimmer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/utils/app_constants.dart'; 4 | import 'package:store_ify/core/widgets/shimmer_widget.dart'; 5 | 6 | class StoresGridViewShimmer extends StatelessWidget { 7 | const StoresGridViewShimmer({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return GridView.builder( 12 | itemCount: 10, 13 | padding: AppConstants.categoryPadding, 14 | physics: AppConstants.physics, 15 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 16 | crossAxisCount: AppConstants.gridCrossAxisCount, 17 | crossAxisSpacing: 8.w, 18 | mainAxisSpacing: 16.h, 19 | childAspectRatio: AppConstants.storeItemAspectRatio, 20 | ), 21 | itemBuilder: (_, __) => const ShimmerWidget(), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/auth/data/models/register_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'register_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | RegisterParams _$RegisterParamsFromJson(Map json) => 10 | RegisterParams( 11 | username: json['username'] as String, 12 | email: json['email'] as String, 13 | password: json['password'] as String, 14 | passwordConfirmation: json['password_confirmation'] as String, 15 | ); 16 | 17 | Map _$RegisterParamsToJson(RegisterParams instance) => 18 | { 19 | 'username': instance.username, 20 | 'email': instance.email, 21 | 'password': instance.password, 22 | 'password_confirmation': instance.passwordConfirmation, 23 | }; 24 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/views/register_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:store_ify/core/di/dependency_injection.dart'; 5 | import 'package:store_ify/features/auth/presentation/cubits/register/register_cubit.dart'; 6 | import 'package:store_ify/features/auth/presentation/widgets/register/register_view_body.dart'; 7 | 8 | @RoutePage() 9 | class RegisterView extends StatelessWidget implements AutoRouteWrapper { 10 | const RegisterView({super.key}); 11 | 12 | @override 13 | Widget wrappedRoute(BuildContext context) { 14 | return BlocProvider( 15 | create: (_) => getIt.get(), 16 | child: this, 17 | ); 18 | } 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return const Scaffold( 23 | body: RegisterViewBody(), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/search/data/models/search_response.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'search_response.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | SearchResponse _$SearchResponseFromJson(Map json) => 10 | SearchResponse( 11 | products: (json['products'] as List) 12 | .map((e) => Product.fromJson(e as Map)) 13 | .toList(), 14 | pagination: json['pagination'] == null 15 | ? null 16 | : Pagination.fromJson(json['pagination'] as Map), 17 | ); 18 | 19 | Map _$SearchResponseToJson(SearchResponse instance) => 20 | { 21 | 'products': instance.products, 22 | 'pagination': instance.pagination, 23 | }; 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Symbolication related 36 | app.*.symbols 37 | 38 | # Obfuscation related 39 | app.*.map.json 40 | 41 | # Android Studio will place build artifacts here 42 | /android/app/debug 43 | /android/app/profile 44 | /android/app/release 45 | 46 | 47 | .vscode 48 | macos 49 | windows 50 | linux 51 | web -------------------------------------------------------------------------------- /lib/core/helpers/hive_keys.dart: -------------------------------------------------------------------------------- 1 | class HiveKeys { 2 | HiveKeys._(); 3 | 4 | static const String homeResponse = 'homeResponse'; 5 | static const String cartResponse = 'cartResponse'; 6 | static const String categoriesResponse = 'categoriesResponse'; 7 | static const String favProductsResponse = 'favProductsResponse'; 8 | static const String favStoresResponse = 'favStoresResponse'; 9 | static const String fetchedStoresResponse = 'fetchedStoresResponse'; 10 | static const String fetchedCategoryStoresResponse = 11 | 'fetchedCategoryStoresResponse'; 12 | static const String fetchedStoreBranchesResponse = 13 | 'fetchedStoreBranchesResponse'; 14 | static const String fetchedStoreCategoriesResponse = 15 | 'fetchedStoreCategoriesResponse'; 16 | static const String fetchedStoreOffersResponse = 'fetchedStoreOffersResponse'; 17 | static const String searchData = 'searchData'; 18 | static const String cardDetails = 'cardDetails'; 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/stores/presentation/cubits/stores/stores_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/features/stores/data/models/fetch_stores_response.dart'; 3 | 4 | part 'stores_state.freezed.dart'; 5 | 6 | enum StoresStateStatus { 7 | initial, 8 | fetchStoresLoading, 9 | fetchStoresSuccess, 10 | fetchStoresError, 11 | fetchCategoryStoresLoading, 12 | fetchCategoryStoresSuccess, 13 | fetchCategoryStoresError, 14 | updateCurrentSelectedStore 15 | } 16 | 17 | @freezed 18 | class StoresState with _$StoresState { 19 | const factory StoresState({ 20 | required StoresStateStatus status, 21 | FetchStoresResponse? stores, 22 | FetchStoresResponse? categoryStores, 23 | String? error, 24 | @Default(0) int currentStoreIndex, 25 | }) = _StoresState; 26 | 27 | factory StoresState.initial() => const StoresState( 28 | status: StoresStateStatus.initial, 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /lib/core/helpers/app_regex.dart: -------------------------------------------------------------------------------- 1 | class AppRegex { 2 | static bool isEmailValid(String email) { 3 | return RegExp(r'^.+@[a-zA-Z]+\.{1}[a-zA-Z]+(\.{0,1}[a-zA-Z]+)$') 4 | .hasMatch(email); 5 | } 6 | 7 | static bool passwordHasSpecialCharacter(String password) { 8 | return RegExp(r"[@$#!%*?&]").hasMatch(password); 9 | } 10 | 11 | static bool passwordHasCapitalCharacter(String password) { 12 | return RegExp(r"[A-Z]").hasMatch(password); 13 | } 14 | 15 | static bool passwordHasLowercaseCharacter(String password) { 16 | return RegExp(r"[a-z]").hasMatch(password); 17 | } 18 | 19 | static bool passwordHasNumber(String password) { 20 | return RegExp(r"\d").hasMatch(password); 21 | } 22 | 23 | static bool containsOnlyDigits(String val) { 24 | return RegExp(r'^[0-9]+$').hasMatch(val); 25 | } 26 | 27 | static bool containsAlphabeticAndSpaces(String val) { 28 | return RegExp(r'^[a-zA-Z\s]+$').hasMatch(val); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/checkout/data/models/checkout_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'checkout_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CheckoutParams _$CheckoutParamsFromJson(Map json) => 10 | CheckoutParams( 11 | username: json['username'] as String, 12 | address: json['address'] as String, 13 | phone: json['phone'] as String, 14 | date: json['date'] as String, 15 | time: json['time'] as String, 16 | ); 17 | 18 | Map _$CheckoutParamsToJson(CheckoutParams instance) => 19 | { 20 | 'username': instance.username, 21 | 'address': instance.address, 22 | 'phone': instance.phone, 23 | 'date': instance.date, 24 | 'time': instance.time, 25 | }; 26 | -------------------------------------------------------------------------------- /lib/features/payment/presentation/widgets/card_details_text.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:easy_localization/easy_localization.dart'; 4 | import 'package:store_ify/generated/locale_keys.g.dart'; 5 | import 'package:store_ify/core/themes/app_colors.dart'; 6 | import 'package:store_ify/core/themes/app_text_styles.dart'; 7 | 8 | class CardDetailsText extends StatelessWidget { 9 | const CardDetailsText({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container( 14 | margin: EdgeInsetsDirectional.only( 15 | start: 14.w, 16 | top: 29.h, 17 | bottom: 27.h, 18 | ), 19 | child: Text( 20 | context.tr(LocaleKeys.cardDetails), 21 | style: AppTextStyles.textStyle20Medium.copyWith( 22 | color: AppColors.primaryColor, 23 | ), 24 | ), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/features/search/data/api/search_api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart'; 3 | import 'package:store_ify/core/api/end_points.dart'; 4 | import 'package:store_ify/features/search/data/models/fetch_search_data_response.dart'; 5 | import 'package:store_ify/features/search/data/models/search_params.dart'; 6 | import 'package:store_ify/features/search/data/models/search_response.dart'; 7 | 8 | part 'search_api_service.g.dart'; 9 | 10 | @RestApi(baseUrl: EndPoints.baseUrl) 11 | abstract class SearchApiService { 12 | factory SearchApiService(Dio dio, {String baseUrl}) = _SearchApiService; 13 | 14 | @POST(EndPoints.search) 15 | Future search( 16 | @Body() SearchParams params, [ 17 | @CancelRequest() CancelToken? cancelToken, 18 | ]); 19 | 20 | @GET(EndPoints.searchData) 21 | Future fetchSearchData([ 22 | @CancelRequest() CancelToken? cancelToken, 23 | ]); 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/stores/presentation/widgets/categories_grid_view_shimmer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/utils/app_constants.dart'; 4 | import 'package:store_ify/core/widgets/shimmer_widget.dart'; 5 | 6 | class CategoriesGridViewShimmer extends StatelessWidget { 7 | const CategoriesGridViewShimmer({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return GridView.builder( 12 | itemCount: 10, 13 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 14 | crossAxisCount: AppConstants.gridCrossAxisCount, 15 | crossAxisSpacing: AppConstants.gridCrossAxisSpacing, 16 | mainAxisSpacing: AppConstants.gridMainAxisSpacing, 17 | ), 18 | itemBuilder: (_, __) => ShimmerWidget( 19 | constraints: BoxConstraints(maxHeight: 165.h, maxWidth: 170.w), 20 | ), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/categories/presentation/cubit/sub_category/sub_category_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/core/models/sub_category.dart'; 3 | import 'package:store_ify/features/categories/data/models/fetch_sub_category_response.dart'; 4 | 5 | part 'sub_category_state.freezed.dart'; 6 | 7 | enum SubCategoryStateStatus { 8 | initial, 9 | fetchSubCategoryLoading, 10 | fetchSubCategorySuccess, 11 | fetchSubCategoryError, 12 | updateSelectedSubCategory, 13 | } 14 | 15 | @freezed 16 | class SubCategoryState with _$SubCategoryState { 17 | const factory SubCategoryState({ 18 | required SubCategoryStateStatus status, 19 | FetchSubCategoryResponse? subCategoryResponse, 20 | String? error, 21 | SubCategory? selectedSubCategory, 22 | }) = _SubCategoryState; 23 | 24 | factory SubCategoryState.initial() => const SubCategoryState( 25 | status: SubCategoryStateStatus.initial, 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /lib/features/profile/data/models/change_password_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'change_password_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | ChangePasswordParams _$ChangePasswordParamsFromJson( 10 | Map json) => 11 | ChangePasswordParams( 12 | currentPassword: json['current_password'] as String, 13 | password: json['password'] as String, 14 | passwordConfirmation: json['password_confirmation'] as String, 15 | ); 16 | 17 | Map _$ChangePasswordParamsToJson( 18 | ChangePasswordParams instance) => 19 | { 20 | 'current_password': instance.currentPassword, 21 | 'password': instance.password, 22 | 'password_confirmation': instance.passwordConfirmation, 23 | }; 24 | -------------------------------------------------------------------------------- /lib/features/cart/presentation/cubit/cart_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/features/cart/data/models/fetch_cart_response.dart'; 3 | 4 | part 'cart_state.freezed.dart'; 5 | 6 | enum CartStateStatus { 7 | initial, 8 | addProductToCartLoading, 9 | addProductToCartSuccess, 10 | addProductToCartError, 11 | fetchCartLoading, 12 | fetchCartSuccess, 13 | fetchCartError, 14 | removeProductFromCartLoading, 15 | removeProductFromCartSuccess, 16 | removeProductFromCartError, 17 | increaseProductQuantity, 18 | decreaseProductQuantity, 19 | } 20 | 21 | @freezed 22 | class CartState with _$CartState { 23 | const factory CartState({ 24 | required CartStateStatus status, 25 | String? error, 26 | FetchCartResponse? cart, 27 | @Default(1) int productQuantity, 28 | }) = _CartState; 29 | 30 | factory CartState.initial() => const CartState( 31 | status: CartStateStatus.initial, 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /lib/features/stores/data/models/fetch_store_offers_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/hive_flutter.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | import 'package:store_ify/core/models/pagination.dart'; 5 | import 'package:store_ify/core/models/product.dart'; 6 | 7 | part 'fetch_store_offers_response.g.dart'; 8 | 9 | @HiveType(typeId: HiveTypeIds.fetchStoreOffersResponse) 10 | @JsonSerializable(explicitToJson: true) 11 | class FetchStoreOffersResponse { 12 | @HiveField(0) 13 | final List products; 14 | @HiveField(1) 15 | final Pagination pagination; 16 | 17 | const FetchStoreOffersResponse({ 18 | required this.products, 19 | required this.pagination, 20 | }); 21 | 22 | factory FetchStoreOffersResponse.fromJson(Map json) => 23 | _$FetchStoreOffersResponseFromJson(json); 24 | Map toJson() => _$FetchStoreOffersResponseToJson(this); 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/widgets/custom_progress_circle.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/themes/app_colors.dart'; 4 | 5 | class CustomProgressCircle extends StatelessWidget { 6 | const CustomProgressCircle({ 7 | super.key, 8 | this.isColoredPrimary = true, 9 | }); 10 | 11 | final bool isColoredPrimary; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Container( 16 | height: 25.87.h, 17 | width: 25.87.h, 18 | decoration: BoxDecoration( 19 | shape: BoxShape.circle, 20 | color: 21 | isColoredPrimary ? AppColors.primaryColor : AppColors.colorD9D9D9, 22 | border: Border.all( 23 | color: 24 | isColoredPrimary ? AppColors.primaryColor : AppColors.colorD9D9D9, 25 | width: isColoredPrimary ? 0 : 1.08.w, 26 | ), 27 | ), 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/widgets/payment_method_process_progress.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/features/checkout/presentation/widgets/check_circle.dart'; 3 | import 'package:store_ify/features/checkout/presentation/widgets/container_contains_dot.dart'; 4 | import 'package:store_ify/features/checkout/presentation/widgets/custom_checkout_divider.dart'; 5 | import 'package:store_ify/features/checkout/presentation/widgets/custom_progress_circle.dart'; 6 | 7 | class PaymentMethodProcessProgress extends StatelessWidget { 8 | const PaymentMethodProcessProgress({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return const Row( 13 | mainAxisAlignment: MainAxisAlignment.center, 14 | children: [ 15 | CustomProgressCircle(), 16 | CustomCheckoutDivider(), 17 | CheckCircle(), 18 | CustomCheckoutDivider(), 19 | ContainerContainsDot(), 20 | ], 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/cubits/payment_method/payment_method_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/core/utils/app_constants.dart'; 3 | import 'package:store_ify/features/checkout/data/models/payment_method.dart'; 4 | 5 | part 'payment_method_state.freezed.dart'; 6 | 7 | enum PaymentMethodStateStatus { 8 | initial, 9 | selectingPaymentMethod, 10 | choosePaymentMethodLoading, 11 | choosePaymentMethodSuccess, 12 | choosePaymentMethodError, 13 | } 14 | 15 | @freezed 16 | class PaymentMethodState with _$PaymentMethodState { 17 | const factory PaymentMethodState({ 18 | required PaymentMethodStateStatus status, 19 | PaymentMethod? selectedPaymentMethod, 20 | String? error, 21 | }) = _PaymentMethodState; 22 | 23 | factory PaymentMethodState.initial() => PaymentMethodState( 24 | status: PaymentMethodStateStatus.initial, 25 | selectedPaymentMethod: AppConstants.paymentMethods[0], 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /lib/features/categories/presentation/widgets/empty_sub_category_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/core/widgets/custom_sliver_app_bar.dart'; 3 | import 'package:store_ify/core/widgets/empty_widget.dart'; 4 | import 'package:store_ify/generated/locale_keys.g.dart'; 5 | 6 | class EmptySubCategoryView extends StatelessWidget { 7 | const EmptySubCategoryView({ 8 | super.key, 9 | required this.appBarTitleText, 10 | }); 11 | 12 | final String appBarTitleText; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return CustomScrollView( 17 | slivers: [ 18 | CustomSliverAppBar(titleText: appBarTitleText), 19 | const SliverFillRemaining( 20 | hasScrollBody: false, 21 | child: EmptyWidget( 22 | titleKey: LocaleKeys.emptySubCategories, 23 | descriptionKey: LocaleKeys.emptySubCategoriesDescription, 24 | ), 25 | ), 26 | ], 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/cubits/update_profile/update_profile_state.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:freezed_annotation/freezed_annotation.dart'; 4 | import 'package:store_ify/core/models/storeify_user.dart'; 5 | 6 | part 'update_profile_state.freezed.dart'; 7 | 8 | enum UpdateProfileStateStatus { 9 | initial, 10 | updateProfileLoading, 11 | updateProfileSuccess, 12 | updateProfileError, 13 | updateSelectedImg, 14 | onChangeEmail, 15 | onChangeUsername, 16 | } 17 | 18 | @freezed 19 | class UpdateProfileState with _$UpdateProfileState { 20 | const factory UpdateProfileState({ 21 | required UpdateProfileStateStatus status, 22 | StoreifyUser? updatedUser, 23 | File? selectedImg, 24 | String? error, 25 | @Default('') String email, 26 | @Default('') String username, 27 | }) = _UpdateProfileState; 28 | 29 | factory UpdateProfileState.initial() => const UpdateProfileState( 30 | status: UpdateProfileStateStatus.initial, 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/dark_mode_switch_bloc_selector.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:store_ify/core/helpers/extensions.dart'; 4 | import 'package:store_ify/core/widgets/custom_adaptive_switch.dart'; 5 | import 'package:store_ify/features/favorites/presentation/cubits/favorites/general_cubit.dart'; 6 | import 'package:store_ify/features/favorites/presentation/cubits/favorites/general_state.dart'; 7 | 8 | class DarkModeSwitchBlocSelector extends StatelessWidget { 9 | const DarkModeSwitchBlocSelector({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return BlocSelector( 14 | selector: (state) => state.theme!, 15 | builder: (context, state) => CustomAdaptiveSwitch( 16 | value: context.isDarkModeActive, 17 | onChanged: (_) => context.read().toggleTheme(), 18 | ), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/core/utils/bloc_observer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | 4 | class MyBlocObserver extends BlocObserver { 5 | @override 6 | void onCreate(BlocBase bloc) { 7 | super.onCreate(bloc); 8 | if (kDebugMode) { 9 | print('onCreate -- ${bloc.runtimeType}'); 10 | } 11 | } 12 | 13 | @override 14 | void onChange(BlocBase bloc, Change change) { 15 | super.onChange(bloc, change); 16 | if (kDebugMode) { 17 | print('onChange -- ${bloc.runtimeType}, $change'); 18 | } 19 | } 20 | 21 | @override 22 | void onError(BlocBase bloc, Object error, StackTrace stackTrace) { 23 | if (kDebugMode) { 24 | print('onError -- ${bloc.runtimeType}, $error'); 25 | } 26 | super.onError(bloc, error, stackTrace); 27 | } 28 | 29 | @override 30 | void onClose(BlocBase bloc) { 31 | super.onClose(bloc); 32 | if (kDebugMode) { 33 | print('onClose -- ${bloc.runtimeType}'); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/categories/data/models/fetch_categories_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/hive_flutter.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | import 'package:store_ify/core/models/pagination.dart'; 5 | import 'package:store_ify/features/categories/data/models/category.dart'; 6 | 7 | part 'fetch_categories_response.g.dart'; 8 | 9 | @HiveType(typeId: HiveTypeIds.fetchCategoriesResponse) 10 | @JsonSerializable(explicitToJson: true) 11 | class FetchCategoriesResponse { 12 | @HiveField(0) 13 | final List categories; 14 | @HiveField(1) 15 | final Pagination pagination; 16 | 17 | const FetchCategoriesResponse({ 18 | required this.categories, 19 | required this.pagination, 20 | }); 21 | 22 | factory FetchCategoriesResponse.fromJson(Map json) => 23 | _$FetchCategoriesResponseFromJson(json); 24 | Map toJson() => _$FetchCategoriesResponseToJson(this); 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/widgets/container_contains_dot.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/helpers/extensions.dart'; 4 | import 'package:store_ify/core/themes/app_colors.dart'; 5 | 6 | class ContainerContainsDot extends StatelessWidget { 7 | const ContainerContainsDot({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | padding: EdgeInsets.all(6.47.h), 13 | decoration: BoxDecoration( 14 | shape: BoxShape.circle, 15 | color: context.isDarkModeActive 16 | ? Colors.transparent 17 | : AppColors.lightModeColor, 18 | border: Border.all( 19 | color: AppColors.colorD9D9D9, 20 | width: 1.08.w, 21 | ), 22 | ), 23 | child: CircleAvatar( 24 | radius: 6.5.r, 25 | backgroundColor: AppColors.primaryColor, 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ios/Runner/GoogleService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | API_KEY 6 | AIzaSyCRb8UgDVHf6MMQUx9PCzjOyYV88u88fIU 7 | GCM_SENDER_ID 8 | 74739450491 9 | PLIST_VERSION 10 | 1 11 | BUNDLE_ID 12 | com.example.storeIfy 13 | PROJECT_ID 14 | store-ify-ecommerce 15 | STORAGE_BUCKET 16 | store-ify-ecommerce.appspot.com 17 | IS_ADS_ENABLED 18 | 19 | IS_ANALYTICS_ENABLED 20 | 21 | IS_APPINVITE_ENABLED 22 | 23 | IS_GCM_ENABLED 24 | 25 | IS_SIGNIN_ENABLED 26 | 27 | GOOGLE_APP_ID 28 | 1:74739450491:ios:bd1f70b20eb2a84e8e58de 29 | 30 | -------------------------------------------------------------------------------- /lib/features/cart/data/models/add_product_to_cart_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'add_product_to_cart_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | AddProductToCartParams _$AddProductToCartParamsFromJson( 10 | Map json) => 11 | AddProductToCartParams( 12 | productId: (json['productId'] as num).toInt(), 13 | quantity: (json['quantity'] as num).toInt(), 14 | sizeId: (json['size_id'] as num?)?.toInt(), 15 | colorId: (json['color_id'] as num?)?.toInt(), 16 | ); 17 | 18 | Map _$AddProductToCartParamsToJson( 19 | AddProductToCartParams instance) => 20 | { 21 | 'productId': instance.productId, 22 | 'color_id': instance.colorId, 23 | 'size_id': instance.sizeId, 24 | 'quantity': instance.quantity, 25 | }; 26 | -------------------------------------------------------------------------------- /lib/features/cart/data/models/cart.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import 'package:store_ify/core/models/product_color.dart'; 3 | import 'package:store_ify/core/models/product.dart'; 4 | import 'package:store_ify/core/models/product_size.dart'; 5 | 6 | part 'cart.g.dart'; 7 | 8 | @JsonSerializable(explicitToJson: true) 9 | class Cart { 10 | final int id; 11 | final int quantity; 12 | final double price; 13 | final double total; 14 | @JsonKey(name: 'cart_id') 15 | final int cartId; 16 | final Product product; 17 | final ProductColor color; 18 | final ProductSize size; 19 | 20 | const Cart({ 21 | required this.id, 22 | required this.quantity, 23 | required this.cartId, 24 | required this.product, 25 | required this.price, 26 | required this.total, 27 | required this.color, 28 | required this.size, 29 | }); 30 | 31 | factory Cart.fromJson(Map json) => _$CartFromJson(json); 32 | Map toJson() => _$CartToJson(this); 33 | } 34 | -------------------------------------------------------------------------------- /lib/features/cart/presentation/widgets/cart_loading_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/core/utils/app_constants.dart'; 3 | import 'package:store_ify/core/widgets/custom_sliver_app_bar.dart'; 4 | import 'package:store_ify/core/widgets/shimmer_widget.dart'; 5 | import 'package:store_ify/generated/locale_keys.g.dart'; 6 | 7 | class CartLoadingView extends StatelessWidget { 8 | const CartLoadingView({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return CustomScrollView( 13 | slivers: [ 14 | const CustomSliverAppBar( 15 | titleKey: LocaleKeys.cart, 16 | hasLeading: false, 17 | ), 18 | SliverList.builder( 19 | itemCount: 8, 20 | itemBuilder: (_, index) => AspectRatio( 21 | aspectRatio: 367 / 109, 22 | child: ShimmerWidget( 23 | margin: AppConstants.cartItemMargin, 24 | ), 25 | ), 26 | ), 27 | ], 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/cart/presentation/widgets/empty_cart_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/core/utils/app_assets.dart'; 3 | import 'package:store_ify/core/widgets/custom_sliver_app_bar.dart'; 4 | import 'package:store_ify/core/widgets/empty_widget.dart'; 5 | import 'package:store_ify/generated/locale_keys.g.dart'; 6 | 7 | class EmptyCartWidget extends StatelessWidget { 8 | const EmptyCartWidget({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return const CustomScrollView( 13 | slivers: [ 14 | CustomSliverAppBar( 15 | titleKey: LocaleKeys.cart, 16 | hasLeading: false, 17 | ), 18 | SliverFillRemaining( 19 | hasScrollBody: false, 20 | child: EmptyWidget( 21 | imagePath: AppAssets.imagesEmptyCart, 22 | titleKey: LocaleKeys.putToYourCart, 23 | descriptionKey: LocaleKeys.putToYourCartToStartShopping), 24 | ), 25 | ], 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/features/payment/presentation/widgets/check_box_bloc_selector.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:store_ify/features/payment/presentation/cubits/payment_cubit.dart'; 5 | import 'package:store_ify/features/payment/presentation/cubits/payment_state.dart'; 6 | 7 | class CheckboxBlocSelector extends StatelessWidget { 8 | const CheckboxBlocSelector({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return BlocSelector( 13 | selector: (state) => state.checkboxValue, 14 | builder: (context, checkboxValue) => Checkbox.adaptive( 15 | value: checkboxValue, 16 | onChanged: (value) => 17 | context.read().toggleCheckBox(value), 18 | shape: RoundedRectangleBorder( 19 | borderRadius: BorderRadius.circular(4.r), 20 | ), 21 | ), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/views/verification_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:store_ify/core/di/dependency_injection.dart'; 5 | import 'package:store_ify/features/auth/presentation/cubits/validate_otp/validate_otp_cubit.dart'; 6 | import 'package:store_ify/features/auth/presentation/widgets/verification/verification_view_body.dart'; 7 | 8 | @RoutePage() 9 | class VerificationView extends StatelessWidget implements AutoRouteWrapper { 10 | const VerificationView({super.key, required this.email}); 11 | 12 | final String email; 13 | 14 | @override 15 | Widget wrappedRoute(BuildContext context) { 16 | return BlocProvider( 17 | create: (_) => getIt.get(), 18 | child: this, 19 | ); 20 | } 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Scaffold( 25 | body: VerificationViewBody(email: email), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/widgets/text_field_label.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:store_ify/core/themes/app_colors.dart'; 5 | import 'package:store_ify/core/themes/app_text_styles.dart'; 6 | 7 | class TextFieldLabel extends StatelessWidget { 8 | const TextFieldLabel({ 9 | super.key, 10 | required this.labelKey, 11 | this.textStyle, 12 | this.margin, 13 | }); 14 | 15 | final String labelKey; 16 | final TextStyle? textStyle; 17 | final EdgeInsetsGeometry? margin; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Container( 22 | margin: margin ?? EdgeInsetsDirectional.only(bottom: 9.h, start: 9.w), 23 | child: Text( 24 | context.tr(labelKey), 25 | style: textStyle ?? 26 | AppTextStyles.textStyle16Regular 27 | .copyWith(color: AppColors.primaryColor), 28 | ), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/features/categories/data/api/categories_api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart'; 3 | import 'package:store_ify/core/api/end_points.dart'; 4 | import 'package:store_ify/features/categories/data/models/fetch_categories_response.dart'; 5 | import 'package:store_ify/features/categories/data/models/fetch_sub_category_response.dart'; 6 | 7 | part 'categories_api_service.g.dart'; 8 | 9 | @RestApi(baseUrl: EndPoints.baseUrl) 10 | abstract class CategoriesApiService { 11 | factory CategoriesApiService(Dio dio, {String baseUrl}) = 12 | _CategoriesApiService; 13 | 14 | @GET(EndPoints.fetchCategories) 15 | Future fetchCategories([ 16 | @CancelRequest() CancelToken? cancelToken, 17 | ]); 18 | 19 | @GET('${EndPoints.fetchCategories}/{category_id}/{sub_category_id}') 20 | Future fetchSubCategory( 21 | @Path('category_id') int categoryId, 22 | @Path('sub_category_id') int subCategoryId, [ 23 | @CancelRequest() CancelToken? cancelToken, 24 | ]); 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/profile_view_sliver_app_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:store_ify/generated/locale_keys.g.dart'; 4 | import 'package:store_ify/core/router/app_router.dart'; 5 | import 'package:store_ify/core/themes/app_colors.dart'; 6 | import 'package:store_ify/core/utils/app_constants.dart'; 7 | import 'package:store_ify/core/widgets/custom_sliver_app_bar.dart'; 8 | 9 | class ProfileViewSliverAppBar extends StatelessWidget { 10 | const ProfileViewSliverAppBar({super.key}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return CustomSliverAppBar( 15 | titleKey: LocaleKeys.profile, 16 | actions: [ 17 | const Icon( 18 | AppConstants.personIcon, 19 | color: AppColors.primaryColor, 20 | ), 21 | IconButton( 22 | onPressed: () => context.pushRoute(const UpdateProfileRoute()), 23 | icon: const Icon(Icons.edit_sharp), 24 | ), 25 | ], 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/features/product_details/presentation/cubit/product_details_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/core/models/product_color.dart'; 3 | import 'package:store_ify/core/models/product_size.dart'; 4 | 5 | part 'product_details_state.freezed.dart'; 6 | 7 | enum ProductDetailsStateStatus { 8 | initial, 9 | selectProductSize, 10 | selectProductColor, 11 | addProductToCartLoading, 12 | addProductToCartSuccess, 13 | addProductToCartError, 14 | increaseProductQuantity, 15 | decreaseProductQuantity, 16 | } 17 | 18 | @freezed 19 | class ProductDetailsState with _$ProductDetailsState { 20 | const factory ProductDetailsState({ 21 | required ProductDetailsStateStatus status, 22 | ProductSize? selectedProductSize, 23 | ProductColor? selectedProductColor, 24 | @Default(1) int productQuantity, 25 | String? error, 26 | }) = _ProductDetailsState; 27 | 28 | factory ProductDetailsState.initial() => const ProductDetailsState( 29 | status: ProductDetailsStateStatus.initial, 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /lib/core/helpers/hive_type_ids.dart: -------------------------------------------------------------------------------- 1 | class HiveTypeIds { 2 | HiveTypeIds._(); 3 | 4 | static const int storeifyUser = 0; 5 | static const int storeifyUserData = 1; 6 | static const int fetchHomeResponse = 2; 7 | static const int product = 3; 8 | static const int productImg = 4; 9 | static const int productColor = 5; 10 | static const int productSize = 6; 11 | static const int store = 7; 12 | static const int category = 8; 13 | static const int pagination = 10; 14 | static const int fetchStores = 11; 15 | static const int subCategory = 12; 16 | static const int fetchCategoriesResponse = 14; 17 | static const int fetchFavoriteProductsResponse = 16; 18 | static const int fetchFavStoresResponse = 17; 19 | static const int fetchStoreBranchesResponse = 18; 20 | static const int fetchStoreCategoriesResponse = 19; 21 | static const int fetchStoreOffersResponse = 20; 22 | static const int storeBranch = 21; 23 | static const int searchData = 22; 24 | static const int searchDataItem = 23; 25 | static const int payParams = 24; 26 | static const int cardType = 25; 27 | } 28 | -------------------------------------------------------------------------------- /lib/features/auth/data/datasources/auth_local_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:store_ify/core/api/dio_factory.dart'; 4 | import 'package:store_ify/core/helpers/secure_storage_helper.dart'; 5 | import 'package:store_ify/core/helpers/cache_keys.dart'; 6 | import 'package:store_ify/core/models/storeify_user.dart'; 7 | 8 | class AuthLocalDatasource { 9 | AuthLocalDatasource._(); 10 | 11 | static Future cacheUser(StoreifyUser user) async { 12 | await SecureStorageHelper.setSecuredString( 13 | CacheKeys.storeifyUser, 14 | json.encode(user.toJson()), 15 | ); 16 | } 17 | 18 | static Future cacheUserAndSetTokenIntoHeaders(StoreifyUser user) async { 19 | await cacheUser(user); 20 | DioFactory.setTokenIntoHeadersAfterLogin(user.token!); 21 | } 22 | 23 | static Future getCachedUser() async { 24 | final cachedUser = 25 | await SecureStorageHelper.getSecuredString(CacheKeys.storeifyUser); 26 | final StoreifyUser user = StoreifyUser.fromJson(json.decode(cachedUser)); 27 | return user; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/features/cart/presentation/widgets/summary_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:easy_localization/easy_localization.dart'; 3 | import 'package:store_ify/core/themes/app_colors.dart'; 4 | import 'package:store_ify/core/themes/app_text_styles.dart'; 5 | 6 | class SummaryInfo extends StatelessWidget { 7 | const SummaryInfo({ 8 | super.key, 9 | required this.nameKey, 10 | required this.price, 11 | }); 12 | 13 | final String nameKey; 14 | final double price; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Row( 19 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 20 | children: [ 21 | Text( 22 | '${context.tr(nameKey)}:', 23 | style: AppTextStyles.textStyle12Regular.copyWith( 24 | color: AppColors.colorBEBEC3, 25 | ), 26 | ), 27 | Text( 28 | '$price LE', 29 | style: AppTextStyles.textStyle12Regular.copyWith( 30 | color: AppColors.colorBEBEC3, 31 | ), 32 | ), 33 | ], 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/widgets/checkout_process_progress_dots.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/core/themes/app_colors.dart'; 3 | import 'package:store_ify/features/checkout/presentation/widgets/check_circle.dart'; 4 | import 'package:store_ify/features/checkout/presentation/widgets/container_contains_dot.dart'; 5 | import 'package:store_ify/features/checkout/presentation/widgets/custom_checkout_divider.dart'; 6 | import 'package:store_ify/features/checkout/presentation/widgets/custom_progress_circle.dart'; 7 | 8 | class CheckoutProcessProgressDots extends StatelessWidget { 9 | const CheckoutProcessProgressDots({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return const Row( 14 | mainAxisAlignment: MainAxisAlignment.center, 15 | children: [ 16 | CheckCircle(), 17 | CustomCheckoutDivider(), 18 | ContainerContainsDot(), 19 | CustomCheckoutDivider(color: AppColors.colorD9D9D9), 20 | CustomProgressCircle(isColoredPrimary: false), 21 | ], 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/widgets/forgot_password/forgot_password_form.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:store_ify/core/widgets/email_text_form_field.dart'; 4 | import 'package:store_ify/generated/locale_keys.g.dart'; 5 | import 'package:store_ify/features/auth/presentation/cubits/forgot_password/forgot_password_cubit.dart'; 6 | import 'package:store_ify/features/auth/presentation/widgets/text_field_label.dart'; 7 | 8 | class ForgotPasswordForm extends StatelessWidget { 9 | const ForgotPasswordForm({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Form( 14 | key: context.read().formKey, 15 | child: Column( 16 | crossAxisAlignment: CrossAxisAlignment.start, 17 | children: [ 18 | const TextFieldLabel(labelKey: LocaleKeys.email), 19 | EmailTextFormField( 20 | controller: context.read().emailController, 21 | ), 22 | ], 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/categories/presentation/widgets/categories_sliver_shimmer_loading.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/utils/app_constants.dart'; 4 | import 'package:store_ify/core/widgets/shimmer_widget.dart'; 5 | 6 | class CategoriesSliverShimmerLoading extends StatelessWidget { 7 | const CategoriesSliverShimmerLoading({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return SliverPadding( 12 | padding: AppConstants.categoriesGridPadding, 13 | sliver: SliverGrid.builder( 14 | itemCount: 10, 15 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 16 | crossAxisCount: AppConstants.gridCrossAxisCount, 17 | crossAxisSpacing: AppConstants.gridCrossAxisSpacing, 18 | mainAxisSpacing: AppConstants.gridMainAxisSpacing, 19 | ), 20 | itemBuilder: (_, __) => ShimmerWidget( 21 | constraints: BoxConstraints(maxHeight: 165.h, maxWidth: 170.w), 22 | ), 23 | ), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/cart/data/api/cart_api_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:retrofit/retrofit.dart'; 3 | import 'package:store_ify/core/api/end_points.dart'; 4 | import 'package:store_ify/features/cart/data/models/add_product_to_cart_params.dart'; 5 | import 'package:store_ify/features/cart/data/models/fetch_cart_response.dart'; 6 | 7 | part 'cart_api_service.g.dart'; 8 | 9 | @RestApi(baseUrl: EndPoints.baseUrl) 10 | abstract class CartApiService { 11 | factory CartApiService(Dio dio, {String baseUrl}) = _CartApiService; 12 | 13 | @POST('${EndPoints.addProductToCart}{productId}') 14 | Future addProductToCart( 15 | @Path('productId') int productId, 16 | @Body() AddProductToCartParams params, [ 17 | @CancelRequest() CancelToken? cancelToken, 18 | ]); 19 | 20 | @GET(EndPoints.cart) 21 | Future fetchCart([ 22 | @CancelRequest() CancelToken? cancelToken, 23 | ]); 24 | 25 | @DELETE('${EndPoints.cart}{product_id}') 26 | Future removeProductFromCart( 27 | @Path('product_id') int productId, [ 28 | @CancelRequest() CancelToken? cancelToken, 29 | ]); 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 ahmedghaly15 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/core/widgets/horizontal_separated_list_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/utils/app_constants.dart'; 4 | import 'package:store_ify/core/widgets/my_sized_box.dart'; 5 | 6 | class HorizontalSeparatedListView extends StatelessWidget { 7 | const HorizontalSeparatedListView({ 8 | super.key, 9 | required this.itemBuilder, 10 | required this.itemCount, 11 | this.padding, 12 | this.separatorWidget, 13 | }); 14 | 15 | final Widget? Function(BuildContext, int) itemBuilder; 16 | final EdgeInsetsGeometry? padding; 17 | final Widget? separatorWidget; 18 | final int itemCount; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return ListView.separated( 23 | padding: padding ?? 24 | EdgeInsetsDirectional.only(end: 16.w, start: 16.w, bottom: 8.h), 25 | physics: AppConstants.physics, 26 | scrollDirection: Axis.horizontal, 27 | itemBuilder: itemBuilder, 28 | separatorBuilder: ((_, __) => separatorWidget ?? MySizedBox.width19), 29 | itemCount: itemCount, 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/features/favorites/presentation/widgets/favorite_products_grid_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; 3 | import 'package:store_ify/core/models/product.dart'; 4 | import 'package:store_ify/core/utils/app_constants.dart'; 5 | import 'package:store_ify/core/widgets/product_item.dart'; 6 | 7 | class FavoriteProductsGridView extends StatelessWidget { 8 | const FavoriteProductsGridView({ 9 | super.key, 10 | required this.products, 11 | }); 12 | 13 | final List products; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return GridView.builder( 18 | itemCount: products.length, 19 | padding: AppConstants.categoryPadding, 20 | gridDelegate: AppConstants.favProductsGridDelegate, 21 | itemBuilder: (_, index) => AnimationConfiguration.staggeredGrid( 22 | position: index, 23 | columnCount: products.length, 24 | duration: AppConstants.gridDuration, 25 | child: ScaleAnimation( 26 | child: ProductItem(product: products[index]), 27 | ), 28 | ), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/features/categories/data/models/fetch_sub_category_response.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'fetch_sub_category_response.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | FetchSubCategoryResponse _$FetchSubCategoryResponseFromJson( 10 | Map json) => 11 | FetchSubCategoryResponse( 12 | category: SubCategory.fromJson(json['category'] as Map), 13 | products: (json['products'] as List) 14 | .map((e) => Product.fromJson(e as Map)) 15 | .toList(), 16 | pagination: 17 | Pagination.fromJson(json['pagination'] as Map), 18 | ); 19 | 20 | Map _$FetchSubCategoryResponseToJson( 21 | FetchSubCategoryResponse instance) => 22 | { 23 | 'category': instance.category.toJson(), 24 | 'products': instance.products.map((e) => e.toJson()).toList(), 25 | 'pagination': instance.pagination.toJson(), 26 | }; 27 | -------------------------------------------------------------------------------- /lib/features/favorites/presentation/cubits/fetch_favorites/fetch_favorites_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/features/favorites/data/models/fetch_fav_stores_response.dart'; 3 | import 'package:store_ify/features/favorites/data/models/fetch_favorite_products_response.dart'; 4 | 5 | part 'fetch_favorites_state.freezed.dart'; 6 | 7 | enum FetchFavoritesStatus { 8 | initial, 9 | fetchFavoriteProductsLoading, 10 | fetchFavoriteProductsSuccess, 11 | fetchFavoriteProductsError, 12 | fetchFavStoresLoading, 13 | fetchFavStoresSuccess, 14 | fetchFavStoresError, 15 | updateSelectedFavCategory, 16 | } 17 | 18 | @freezed 19 | class FetchFavoritesState with _$FetchFavoritesState { 20 | const factory FetchFavoritesState({ 21 | required FetchFavoritesStatus status, 22 | FetchFavoriteProductsResponse? favProducts, 23 | FetchFavStoresResponse? favStores, 24 | String? error, 25 | @Default(0) int selectedFavCategory, 26 | }) = _FetchFavoritesState; 27 | 28 | factory FetchFavoritesState.initial() => const FetchFavoritesState( 29 | status: FetchFavoritesStatus.initial, 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /lib/features/cart/presentation/widgets/control_cart_product_quantity.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/core/themes/app_colors.dart'; 3 | 4 | class ControlCartProductQuantity extends StatelessWidget { 5 | const ControlCartProductQuantity({ 6 | super.key, 7 | required this.icon, 8 | required this.onTap, 9 | required this.borderRadius, 10 | }); 11 | 12 | final BorderRadiusGeometry borderRadius; 13 | final IconData icon; 14 | final VoidCallback? onTap; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Container( 19 | decoration: BoxDecoration( 20 | borderRadius: borderRadius, 21 | color: AppColors.primaryColor, 22 | ), 23 | child: MaterialButton( 24 | padding: EdgeInsets.zero, 25 | materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, 26 | shape: RoundedRectangleBorder( 27 | borderRadius: borderRadius, 28 | ), 29 | minWidth: 0, 30 | height: 0, 31 | onPressed: onTap, 32 | child: Icon( 33 | icon, 34 | color: Colors.white, 35 | ), 36 | ), 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/features/categories/data/models/category.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/hive_flutter.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | import 'package:store_ify/core/models/product.dart'; 5 | import 'package:store_ify/core/models/sub_category.dart'; 6 | 7 | part 'category.g.dart'; 8 | 9 | @HiveType(typeId: HiveTypeIds.category) 10 | @JsonSerializable(explicitToJson: true) 11 | class Category { 12 | @HiveField(0) 13 | final int id; 14 | @HiveField(1) 15 | final String name; 16 | @HiveField(2) 17 | final String? description; 18 | @HiveField(3) 19 | final String? img; 20 | @HiveField(4) 21 | @JsonKey(name: 'sub_categories') 22 | final List? subCategories; 23 | @HiveField(5) 24 | final List? products; 25 | 26 | const Category({ 27 | required this.id, 28 | required this.name, 29 | this.description, 30 | this.img, 31 | this.subCategories, 32 | this.products, 33 | }); 34 | 35 | factory Category.fromJson(Map json) => 36 | _$CategoryFromJson(json); 37 | Map toJson() => _$CategoryToJson(this); 38 | } 39 | -------------------------------------------------------------------------------- /lib/core/models/pagination.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/hive_flutter.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | 5 | part 'pagination.g.dart'; 6 | 7 | @HiveType(typeId: HiveTypeIds.pagination) 8 | @JsonSerializable() 9 | class Pagination { 10 | @HiveField(0) 11 | final int total; 12 | @HiveField(1) 13 | @JsonKey(name: 'per_page') 14 | final int perPage; 15 | @HiveField(2) 16 | @JsonKey(name: 'current_page') 17 | final int currentPage; 18 | @HiveField(3) 19 | @JsonKey(name: 'last_page') 20 | final int lastPage; 21 | @HiveField(4) 22 | @JsonKey(name: 'next_page_url') 23 | final String? nextPageUrl; 24 | @HiveField(5) 25 | @JsonKey(name: 'prev_page_url') 26 | final String? prevPageUrl; 27 | 28 | const Pagination({ 29 | required this.total, 30 | required this.perPage, 31 | required this.currentPage, 32 | required this.lastPage, 33 | this.nextPageUrl, 34 | this.prevPageUrl, 35 | }); 36 | 37 | factory Pagination.fromJson(Map json) => 38 | _$PaginationFromJson(json); 39 | Map toJson() => _$PaginationToJson(this); 40 | } 41 | -------------------------------------------------------------------------------- /lib/features/checkout/data/models/checkout_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'checkout_response.g.dart'; 4 | 5 | @JsonSerializable(explicitToJson: true) 6 | class CheckoutResponse { 7 | final Order order; 8 | 9 | const CheckoutResponse({required this.order}); 10 | 11 | factory CheckoutResponse.fromJson(Map json) => 12 | _$CheckoutResponseFromJson(json); 13 | Map toJson() => _$CheckoutResponseToJson(this); 14 | } 15 | 16 | @JsonSerializable() 17 | class Order { 18 | final int id; 19 | @JsonKey(name: 'user_id') 20 | final int userId; 21 | final double total; 22 | final String status; 23 | @JsonKey(name: 'delivery_date') 24 | final String deliveryDate; 25 | @JsonKey(name: 'delivery_time') 26 | final String deliveryTime; 27 | 28 | const Order({ 29 | required this.id, 30 | required this.userId, 31 | required this.total, 32 | required this.status, 33 | required this.deliveryDate, 34 | required this.deliveryTime, 35 | }); 36 | 37 | factory Order.fromJson(Map json) => _$OrderFromJson(json); 38 | Map toJson() => _$OrderToJson(this); 39 | } 40 | -------------------------------------------------------------------------------- /lib/core/models/store.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/hive_flutter.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | import 'package:store_ify/features/categories/data/models/category.dart'; 5 | 6 | part 'store.g.dart'; 7 | 8 | @HiveType(typeId: HiveTypeIds.store) 9 | @JsonSerializable(explicitToJson: true, fieldRename: FieldRename.snake) 10 | class Store { 11 | @HiveField(0) 12 | final int id; 13 | @HiveField(1) 14 | final String name; 15 | @HiveField(2) 16 | final String img; 17 | @HiveField(3) 18 | final List? categories; 19 | @HiveField(4) 20 | final int totalProductsOrdered; 21 | @HiveField(5) 22 | final bool isFavorited; 23 | @HiveField(6) 24 | final String averageRating; 25 | 26 | Store({ 27 | required this.id, 28 | required this.name, 29 | required this.img, 30 | required this.categories, 31 | required this.totalProductsOrdered, 32 | required this.isFavorited, 33 | required this.averageRating, 34 | }); 35 | 36 | factory Store.fromJson(Map json) => _$StoreFromJson(json); 37 | Map toJson() => _$StoreToJson(this); 38 | } 39 | -------------------------------------------------------------------------------- /lib/features/onboarding/presentation/widgets/custom_indicators.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:smooth_page_indicator/smooth_page_indicator.dart'; 5 | import 'package:store_ify/core/helpers/extensions.dart'; 6 | import 'package:store_ify/core/themes/app_colors.dart'; 7 | import 'package:store_ify/core/utils/app_constants.dart'; 8 | import 'package:store_ify/features/onboarding/presentation/cubit/onboarding_cubit.dart'; 9 | 10 | class CustomIndicators extends StatelessWidget { 11 | const CustomIndicators({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return SmoothPageIndicator( 16 | controller: context.read().pageController, 17 | count: AppConstants.onboardingPages.length, 18 | effect: ExpandingDotsEffect( 19 | dotColor: context.isDarkModeActive ? Colors.white : Colors.grey, 20 | activeDotColor: AppColors.primaryColor, 21 | dotHeight: 6.h, 22 | expansionFactor: 5.w, 23 | dotWidth: 6.h, 24 | spacing: 5.w, 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/features/cart/data/models/fetch_cart_response.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'fetch_cart_response.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | FetchCartResponse _$FetchCartResponseFromJson(Map json) => 10 | FetchCartResponse( 11 | cart: (json['cart'] as List) 12 | .map((e) => Cart.fromJson(e as Map)) 13 | .toList(), 14 | totalItems: (json['totalItems'] as num).toInt(), 15 | totalPrice: (json['totalPrice'] as num).toDouble(), 16 | subTotalPrice: (json['subTotalPrice'] as num).toDouble(), 17 | delivery: (json['delivery'] as num).toInt(), 18 | ); 19 | 20 | Map _$FetchCartResponseToJson(FetchCartResponse instance) => 21 | { 22 | 'cart': instance.cart.map((e) => e.toJson()).toList(), 23 | 'totalItems': instance.totalItems, 24 | 'delivery': instance.delivery, 25 | 'totalPrice': instance.totalPrice, 26 | 'subTotalPrice': instance.subTotalPrice, 27 | }; 28 | -------------------------------------------------------------------------------- /lib/core/utils/auto_route_observer.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AppRoutesObserver extends AutoRouterObserver { 5 | @override 6 | void didPush(Route route, Route? previousRoute) { 7 | debugPrint('Previous route : ${previousRoute?.settings.name}'); 8 | debugPrint('New route pushed: ${route.settings.name}'); 9 | } 10 | 11 | @override 12 | void didPop(Route route, Route? previousRoute) { 13 | debugPrint('Route Popped : ${route.settings.name}'); 14 | } 15 | 16 | @override 17 | void didRemove(Route route, Route? previousRoute) { 18 | debugPrint('Route Removed : ${route.settings.name}'); 19 | } 20 | 21 | @override 22 | void didReplace({Route? newRoute, Route? oldRoute}) { 23 | debugPrint( 24 | 'OldRoute : ${oldRoute!.settings.name} was replaced by ${newRoute!.settings.name}'); 25 | } 26 | 27 | @override 28 | void didInitTabRoute(TabPageRoute route, TabPageRoute? previousRoute) { 29 | debugPrint('Tab route visited: ${route.name}'); 30 | } 31 | 32 | @override 33 | void didChangeTabRoute(TabPageRoute route, TabPageRoute previousRoute) { 34 | debugPrint('Tab route re-visited: ${route.name}'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/home/data/models/fetch_home_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/hive_flutter.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | import 'package:store_ify/core/models/pagination.dart'; 5 | import 'package:store_ify/core/models/product.dart'; 6 | import 'package:store_ify/features/categories/data/models/category.dart'; 7 | import 'package:store_ify/core/models/store.dart'; 8 | 9 | part 'fetch_home_response.g.dart'; 10 | 11 | @HiveType(typeId: HiveTypeIds.fetchHomeResponse) 12 | @JsonSerializable(explicitToJson: true) 13 | class FetchHomeResponse { 14 | @HiveField(0) 15 | final List bestSelling; 16 | @HiveField(1) 17 | final List categories; 18 | @HiveField(2) 19 | final List topStores; 20 | @HiveField(3) 21 | final Pagination pagination; 22 | 23 | const FetchHomeResponse({ 24 | required this.bestSelling, 25 | required this.categories, 26 | required this.topStores, 27 | required this.pagination, 28 | }); 29 | 30 | factory FetchHomeResponse.fromJson(Map json) => 31 | _$FetchHomeResponseFromJson(json); 32 | Map toJson() => _$FetchHomeResponseToJson(this); 33 | } 34 | -------------------------------------------------------------------------------- /lib/features/cart/data/models/cart.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'cart.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Cart _$CartFromJson(Map json) => Cart( 10 | id: (json['id'] as num).toInt(), 11 | quantity: (json['quantity'] as num).toInt(), 12 | cartId: (json['cart_id'] as num).toInt(), 13 | product: Product.fromJson(json['product'] as Map), 14 | price: (json['price'] as num).toDouble(), 15 | total: (json['total'] as num).toDouble(), 16 | color: ProductColor.fromJson(json['color'] as Map), 17 | size: ProductSize.fromJson(json['size'] as Map), 18 | ); 19 | 20 | Map _$CartToJson(Cart instance) => { 21 | 'id': instance.id, 22 | 'quantity': instance.quantity, 23 | 'price': instance.price, 24 | 'total': instance.total, 25 | 'cart_id': instance.cartId, 26 | 'product': instance.product.toJson(), 27 | 'color': instance.color.toJson(), 28 | 'size': instance.size.toJson(), 29 | }; 30 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/profile_img.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/themes/app_colors.dart'; 4 | import 'package:store_ify/core/utils/app_constants.dart'; 5 | import 'package:store_ify/core/widgets/custom_cached_network_image.dart'; 6 | 7 | class ProfileImg extends StatelessWidget { 8 | const ProfileImg({super.key, this.radius = 30}); 9 | 10 | final double radius; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return ValueListenableBuilder( 15 | valueListenable: userNotifier, 16 | builder: (context, user, __) => CustomCachedNetworkImage( 17 | imageUrl: user!.user.img != 'http://192.168.1.6:8081/uploads' 18 | ? user.user.img! 19 | : 'https://img.freepik.com/free-photo/confident-handsome-guy-posing-against-white-wall_176420-32936.jpg?t=st=1726145242~exp=1726148842~hmac=d88f0854b224a4b284dd8236414a4e0854ca07915b501ad2375b8032fed3456e&w=1060', 20 | imageBuilder: (_, image) => CircleAvatar( 21 | radius: radius.r, 22 | backgroundImage: image, 23 | backgroundColor: AppColors.primaryColor, 24 | ), 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/features/payment/presentation/cubits/payment_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | import 'package:store_ify/core/utils/app_constants.dart'; 4 | import 'package:store_ify/features/payment/data/models/card_type.dart'; 5 | import 'package:store_ify/features/payment/data/models/payment_card_details.dart'; 6 | 7 | part 'payment_state.freezed.dart'; 8 | 9 | enum PaymentStateStatus { 10 | initial, 11 | updateSelectedCardType, 12 | alwaysAutoValidateMode, 13 | toggleCheckBox, 14 | payLoading, 15 | paySuccess, 16 | payError, 17 | retrieveCachedPaymentCardDetails, 18 | retrievedCachedPaymentCardDetails, 19 | } 20 | 21 | @freezed 22 | class PaymentState with _$PaymentState { 23 | const factory PaymentState({ 24 | required PaymentStateStatus status, 25 | CardType? selectedCardType, 26 | @Default(AutovalidateMode.disabled) AutovalidateMode autovalidateMode, 27 | @Default(false) bool checkboxValue, 28 | String? error, 29 | PaymentCardDetails? paymentCardDetails, 30 | }) = _PaymentState; 31 | 32 | factory PaymentState.initial() => PaymentState( 33 | status: PaymentStateStatus.initial, 34 | selectedCardType: AppConstants.cardTypes[0], 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/payment/data/models/payment_card_details.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hive_flutter/hive_flutter.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | import 'package:store_ify/features/payment/data/models/card_type.dart'; 5 | 6 | part 'payment_card_details.g.dart'; 7 | 8 | @HiveType(typeId: HiveTypeIds.payParams) 9 | @JsonSerializable(explicitToJson: true) 10 | class PaymentCardDetails { 11 | @HiveField(0) 12 | final String? number; 13 | @HiveField(1) 14 | final String? cvv; 15 | @HiveField(2) 16 | final String? amount; 17 | @HiveField(3) 18 | @JsonKey(name: 'exp_month') 19 | final String? expMonth; 20 | @HiveField(4) 21 | @JsonKey(name: 'exp_year') 22 | final String? expYear; 23 | @HiveField(5) 24 | final CardType? cardType; 25 | @HiveField(6) 26 | final int? holderNumber; 27 | 28 | PaymentCardDetails({ 29 | this.number, 30 | this.cvv, 31 | this.amount, 32 | this.expMonth, 33 | this.expYear, 34 | this.cardType, 35 | this.holderNumber, 36 | }); 37 | 38 | factory PaymentCardDetails.fromJson(Map json) => 39 | _$PaymentCardDetailsFromJson(json); 40 | Map toJson() => _$PaymentCardDetailsToJson(this); 41 | } 42 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/widgets/how_do_u_want_to_pay_question.dart: -------------------------------------------------------------------------------- 1 | import 'package:animate_do/animate_do.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:easy_localization/easy_localization.dart'; 5 | import 'package:store_ify/generated/locale_keys.g.dart'; 6 | import 'package:store_ify/core/themes/app_colors.dart'; 7 | import 'package:store_ify/core/themes/app_text_styles.dart'; 8 | import 'package:store_ify/core/utils/app_constants.dart'; 9 | 10 | class HowDoUWantToPayQuestion extends StatelessWidget { 11 | const HowDoUWantToPayQuestion({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return FadeInDown( 16 | from: 30.h, 17 | child: Container( 18 | margin: EdgeInsetsDirectional.only( 19 | start: AppConstants.mainButtonHorizontalMarginVal.w, 20 | end: AppConstants.mainButtonHorizontalMarginVal.w, 21 | top: 32.h, 22 | bottom: 40.h, 23 | ), 24 | child: Text( 25 | context.tr(LocaleKeys.howDoUWantToPay), 26 | style: AppTextStyles.textStyle16Medium.copyWith( 27 | color: AppColors.primaryColor, 28 | ), 29 | ), 30 | ), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/core/models/storeify_user.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hive_flutter/hive_flutter.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | 5 | part 'storeify_user.freezed.dart'; 6 | part 'storeify_user.g.dart'; 7 | 8 | @HiveType(typeId: HiveTypeIds.storeifyUser) 9 | @freezed 10 | class StoreifyUser with _$StoreifyUser { 11 | @JsonSerializable(explicitToJson: true) 12 | const factory StoreifyUser({ 13 | @HiveField(0) String? token, 14 | @HiveField(1) required UserData user, 15 | }) = _StoreifyUser; 16 | 17 | factory StoreifyUser.fromJson(Map json) => 18 | _$StoreifyUserFromJson(json); 19 | } 20 | 21 | @HiveType(typeId: HiveTypeIds.storeifyUserData) 22 | @JsonSerializable() 23 | class UserData { 24 | @HiveField(0) 25 | final int id; 26 | @HiveField(1) 27 | final String username; 28 | @HiveField(2) 29 | final String email; 30 | @HiveField(3) 31 | final String? img; 32 | 33 | const UserData({ 34 | required this.id, 35 | required this.username, 36 | required this.email, 37 | this.img, 38 | }); 39 | 40 | factory UserData.fromJson(Map json) => 41 | _$UserDataFromJson(json); 42 | Map toJson() => _$UserDataToJson(this); 43 | } 44 | -------------------------------------------------------------------------------- /lib/core/utils/functions/circular_indicator_or_text_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | import 'package:store_ify/core/helpers/extensions.dart'; 5 | import 'package:store_ify/core/themes/app_colors.dart'; 6 | import 'package:store_ify/core/themes/app_text_styles.dart'; 7 | import 'package:store_ify/core/widgets/custom_circular_progress_indicator.dart'; 8 | 9 | Widget circularIndicatorOrTextWidget({ 10 | required bool isLoading, 11 | required BuildContext context, 12 | required String textKey, 13 | bool isOutlined = false, 14 | }) { 15 | return isLoading 16 | ? SizedBox.square( 17 | dimension: 24.h, 18 | child: CustomCircularProgressIndicator( 19 | color: isOutlined 20 | ? AppColors.primaryColor 21 | : (context.isDarkModeActive 22 | ? AppColors.darkColor 23 | : AppColors.lightModeColor), 24 | ), 25 | ) 26 | : Text( 27 | context.tr(textKey), 28 | style: AppTextStyles.textStyle16Medium.copyWith( 29 | color: isOutlined ? AppColors.primaryColor : Colors.white, 30 | ), 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /lib/features/stores/data/models/fetch_store_branches.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:hive_flutter/hive_flutter.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | 5 | part 'fetch_store_branches.g.dart'; 6 | 7 | @HiveType(typeId: HiveTypeIds.fetchStoreBranchesResponse) 8 | @JsonSerializable(explicitToJson: true) 9 | class FetchStoreBranchesResponse { 10 | @HiveField(0) 11 | final List branches; 12 | 13 | const FetchStoreBranchesResponse({required this.branches}); 14 | 15 | factory FetchStoreBranchesResponse.fromJson(Map json) => 16 | _$FetchStoreBranchesResponseFromJson(json); 17 | Map toJson() => _$FetchStoreBranchesResponseToJson(this); 18 | } 19 | 20 | @HiveType(typeId: HiveTypeIds.storeBranch) 21 | @JsonSerializable() 22 | class StoreBranch { 23 | @HiveField(0) 24 | final int id; 25 | @HiveField(1) 26 | final String name; 27 | @HiveField(2) 28 | final String address; 29 | 30 | const StoreBranch({ 31 | required this.id, 32 | required this.name, 33 | required this.address, 34 | }); 35 | 36 | factory StoreBranch.fromJson(Map json) => 37 | _$StoreBranchFromJson(json); 38 | Map toJson() => _$StoreBranchToJson(this); 39 | } 40 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /lib/core/utils/functions/execute_and_handle_errors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/core/api/api_error_handler.dart'; 3 | import 'package:store_ify/core/api/api_result.dart'; 4 | 5 | /// Executes a given asynchronous function and handles any errors that occur during its execution. 6 | /// 7 | /// This method takes a [function] that returns a [Future] and attempts to execute it. 8 | /// If the function completes successfully, the result is wrapped in an [ApiResult.success] object and returned. 9 | /// If an error occurs during execution, the error is caught, logged using [debugPrint], and 10 | /// an [ApiResult.error] object is returned with the error handled by [ApiErrorHandler]. 11 | /// 12 | /// Example usage: 13 | /// ```dart 14 | /// Future> result = executeAndHandleErrors(() async { 15 | /// // Your asynchronous code here 16 | /// }); 17 | /// ``` 18 | /// 19 | /// [T] is the type of the result that the function returns. 20 | Future> executeAndHandleErrors( 21 | Future Function() function, 22 | ) async { 23 | try { 24 | return ApiResult.success(await function()); 25 | } catch (error) { 26 | debugPrint('********* Error in executeAndHandleErrors: $error **********'); 27 | return ApiResult.error(ApiErrorHandler.handle(error)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /lib/features/favorites/presentation/cubits/favorites/general_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | import 'package:store_ify/core/themes/app_themes.dart'; 4 | import 'package:store_ify/features/home/data/models/fetch_home_response.dart'; 5 | 6 | part 'general_state.freezed.dart'; 7 | 8 | enum GeneralStateStatus { 9 | initial, 10 | preferProductLoading, 11 | preferProductSuccess, 12 | preferProductError, 13 | removeProductFromFavsLoading, 14 | removeProductFromFavsSuccess, 15 | removeProductFromFavsError, 16 | preferStoreLoading, 17 | preferStoreSuccess, 18 | preferStoreError, 19 | removeStoreFromFavsLoading, 20 | removeStoreFromFavsSuccess, 21 | removeStoreFromFavsError, 22 | toggleTheme, 23 | fetchHomeDataLoading, 24 | fetchHomeDataSuccess, 25 | fetchHomeDataError, 26 | } 27 | 28 | @freezed 29 | class GeneralState with _$GeneralState { 30 | const factory GeneralState({ 31 | required GeneralStateStatus status, 32 | String? error, 33 | ThemeData? theme, 34 | FetchHomeResponse? homeData, 35 | int? favAffectedItem, 36 | }) = _GeneralState; 37 | 38 | factory GeneralState.initial() => GeneralState( 39 | status: GeneralStateStatus.initial, 40 | theme: AppThemes.lightMode, 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /lib/features/onboarding/presentation/widgets/next_button_bloc_selector.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 5 | import 'package:store_ify/core/router/app_router.dart'; 6 | import 'package:store_ify/core/widgets/main_button.dart'; 7 | import 'package:store_ify/features/onboarding/presentation/cubit/onboarding_cubit.dart'; 8 | import 'package:store_ify/features/onboarding/presentation/cubit/onboarding_state.dart'; 9 | import 'package:store_ify/generated/locale_keys.g.dart'; 10 | 11 | class NextButtonBlocSelector extends StatelessWidget { 12 | const NextButtonBlocSelector({super.key}); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return BlocSelector( 17 | selector: (state) => state.isLastPage, 18 | builder: (context, isLastPage) => MainButton( 19 | margin: EdgeInsets.symmetric(horizontal: 61.w), 20 | onPressed: () => context.read().navigateAmongPages( 21 | onSkip: () => context.replaceRoute(const LoginRoute()), 22 | ), 23 | textKey: isLastPage ? LocaleKeys.getStarted : LocaleKeys.next, 24 | ), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/features/checkout/presentation/widgets/enable_location_error_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:store_ify/core/widgets/custom_error_widget.dart'; 4 | import 'package:store_ify/core/widgets/custom_sliver_app_bar.dart'; 5 | import 'package:store_ify/features/checkout/presentation/cubits/checkout/checkout_cubit.dart'; 6 | import 'package:store_ify/generated/locale_keys.g.dart'; 7 | 8 | class EnableLocationErrorWidget extends StatelessWidget { 9 | const EnableLocationErrorWidget({ 10 | super.key, 11 | required this.error, 12 | }); 13 | 14 | final String error; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return CustomScrollView( 19 | slivers: [ 20 | const CustomSliverAppBar(titleKey: LocaleKeys.checkout), 21 | SliverFillRemaining( 22 | hasScrollBody: false, 23 | child: CustomErrorWidget( 24 | errorKey: error, 25 | errorDescriptionKey: error == LocaleKeys.locationDenied 26 | ? LocaleKeys.locationDeniedDescription 27 | : null, 28 | tryAgainOnPressed: () => 29 | context.read().enableLocationPermission(), 30 | ), 31 | ), 32 | ], 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/core/widgets/custom_cached_network_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:store_ify/core/themes/app_colors.dart'; 4 | 5 | class CustomCachedNetworkImage extends StatelessWidget { 6 | const CustomCachedNetworkImage({ 7 | super.key, 8 | required this.imageUrl, 9 | this.fit = BoxFit.cover, 10 | this.imageBuilder, 11 | this.height, 12 | this.width, 13 | this.fadeInDuration = const Duration(milliseconds: 500), 14 | this.fadeOutDuration = const Duration(milliseconds: 1000), 15 | }); 16 | 17 | final String imageUrl; 18 | final BoxFit fit; 19 | final Widget Function(BuildContext, ImageProvider)? imageBuilder; 20 | final double? height, width; 21 | final Duration fadeInDuration; 22 | final Duration? fadeOutDuration; 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return CachedNetworkImage( 27 | imageUrl: imageUrl, 28 | fit: fit, 29 | width: height, 30 | height: width, 31 | imageBuilder: imageBuilder, 32 | fadeInDuration: fadeInDuration, 33 | fadeOutDuration: fadeOutDuration, 34 | errorWidget: (_, __, ___) => const Icon( 35 | Icons.error, 36 | color: AppColors.primaryColor, 37 | ), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/core/widgets/email_text_form_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/core/helpers/extensions.dart'; 3 | import 'package:store_ify/core/helpers/text_form_validator.dart'; 4 | import 'package:store_ify/core/widgets/custom_text_field.dart'; 5 | import 'package:store_ify/generated/locale_keys.g.dart'; 6 | 7 | class EmailTextFormField extends StatelessWidget { 8 | const EmailTextFormField({ 9 | super.key, 10 | this.controller, 11 | this.emailFocusNode, 12 | this.nextFocusNode, 13 | this.onChanged, 14 | }); 15 | 16 | final TextEditingController? controller; 17 | final FocusNode? emailFocusNode, nextFocusNode; 18 | final void Function(String)? onChanged; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return CustomTextField( 23 | validate: (String? value) => 24 | TextFormValidator.validateEmailField(context, value: value), 25 | controller: controller, 26 | keyboardType: TextInputType.emailAddress, 27 | hintTextKey: LocaleKeys.emailFieldHint, 28 | autofillHints: const [AutofillHints.email], 29 | focusNode: emailFocusNode, 30 | onEditingComplete: nextFocusNode != null 31 | ? () => context.requestFocus(nextFocusNode!) 32 | : null, 33 | onChanged: onChanged, 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/categories/presentation/cubit/categories/categories_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:store_ify/features/categories/data/repositories/categories_repo.dart'; 4 | import 'package:store_ify/features/categories/presentation/cubit/categories/categories_state.dart'; 5 | 6 | class CategoriesCubit extends Cubit { 7 | CategoriesCubit(this._categoriesRepo) : super(CategoriesState.initial()); 8 | 9 | final CategoriesRepo _categoriesRepo; 10 | final CancelToken _cancelToken = CancelToken(); 11 | 12 | Future fetchCategories() async { 13 | emit(state.copyWith( 14 | status: CategoriesStateStatus.fetchCategoriesLoading, 15 | )); 16 | final result = await _categoriesRepo.fetchCategories(_cancelToken); 17 | result.when( 18 | success: (categoriesResponse) => emit(state.copyWith( 19 | status: CategoriesStateStatus.fetchCategoriesSuccess, 20 | categoriesResponse: categoriesResponse, 21 | )), 22 | error: (errorModel) => emit(state.copyWith( 23 | status: CategoriesStateStatus.fetchCategoriesError, 24 | error: errorModel.error ?? '', 25 | )), 26 | ); 27 | } 28 | 29 | @override 30 | Future close() { 31 | _cancelToken.cancel(); 32 | return super.close(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "LaunchImage.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "filename" : "LaunchImageDark.png", 16 | "idiom" : "universal", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "filename" : "LaunchImage@2x.png", 21 | "idiom" : "universal", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "appearances" : [ 26 | { 27 | "appearance" : "luminosity", 28 | "value" : "dark" 29 | } 30 | ], 31 | "filename" : "LaunchImageDark@2x.png", 32 | "idiom" : "universal", 33 | "scale" : "2x" 34 | }, 35 | { 36 | "filename" : "LaunchImage@3x.png", 37 | "idiom" : "universal", 38 | "scale" : "3x" 39 | }, 40 | { 41 | "appearances" : [ 42 | { 43 | "appearance" : "luminosity", 44 | "value" : "dark" 45 | } 46 | ], 47 | "filename" : "LaunchImageDark@3x.png", 48 | "idiom" : "universal", 49 | "scale" : "3x" 50 | } 51 | ], 52 | "info" : { 53 | "author" : "xcode", 54 | "version" : 1 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/core/widgets/username_text_form_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/core/helpers/extensions.dart'; 3 | import 'package:store_ify/core/helpers/text_form_validator.dart'; 4 | import 'package:store_ify/core/widgets/custom_text_field.dart'; 5 | import 'package:store_ify/generated/locale_keys.g.dart'; 6 | 7 | class UsernameTextFormField extends StatelessWidget { 8 | const UsernameTextFormField({ 9 | super.key, 10 | this.controller, 11 | this.usernameFocusNode, 12 | this.nextFocusNode, 13 | this.onChanged, 14 | }); 15 | 16 | final TextEditingController? controller; 17 | final FocusNode? usernameFocusNode, nextFocusNode; 18 | final void Function(String)? onChanged; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return CustomTextField( 23 | validate: (String? value) => 24 | TextFormValidator.validateNameField(context, value: value), 25 | controller: controller, 26 | keyboardType: TextInputType.name, 27 | hintTextKey: LocaleKeys.enterYourUsername, 28 | autofillHints: const [AutofillHints.name], 29 | focusNode: usernameFocusNode, 30 | onEditingComplete: nextFocusNode != null 31 | ? () => context.requestFocus(nextFocusNode!) 32 | : null, 33 | onChanged: onChanged, 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/payment/data/datasource/payment_local_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hive_flutter/hive_flutter.dart'; 3 | import 'package:store_ify/core/helpers/hive_boxes.dart'; 4 | import 'package:store_ify/core/helpers/hive_keys.dart'; 5 | import 'package:store_ify/features/payment/data/models/payment_card_details.dart'; 6 | 7 | class PaymentLocalDatasource { 8 | PaymentLocalDatasource._(); 9 | 10 | static Future cacheCardDetails(PaymentCardDetails payParams) async { 11 | final box = 12 | await Hive.openLazyBox(HiveBoxes.paymentBox); 13 | debugPrint('********** CACHED PAYMENT CARD DETAILS **********'); 14 | await box.put(HiveKeys.cardDetails, payParams); 15 | } 16 | 17 | static Future retrieveCachedCardDetails() async { 18 | final box = 19 | await Hive.openLazyBox(HiveBoxes.paymentBox); 20 | debugPrint('******** RETRIEVED CACHED PAYMENT CARD DETAILS ***********'); 21 | return box.get(HiveKeys.cardDetails); 22 | } 23 | 24 | static Future deleteCachedCardDetails() async { 25 | final box = 26 | await Hive.openLazyBox(HiveBoxes.paymentBox); 27 | debugPrint('********* DELETED CACHED PAYMENT CARD DETAILS *********'); 28 | await box.delete(HiveKeys.cardDetails); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /lib/features/home/data/datasources/home_local_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hive_flutter/hive_flutter.dart'; 3 | import 'package:store_ify/core/helpers/hive_boxes.dart'; 4 | import 'package:store_ify/core/helpers/hive_keys.dart'; 5 | import 'package:store_ify/core/utils/app_constants.dart'; 6 | import 'package:store_ify/features/home/data/models/fetch_home_response.dart'; 7 | 8 | class HomeLocalDatasource { 9 | const HomeLocalDatasource(); 10 | 11 | Future cacheHomeResponse(FetchHomeResponse homeResponse) async { 12 | final box = 13 | await Hive.openLazyBox(HiveBoxes.homeResponseBox); 14 | debugPrint('********* CACHED HOME RESPONSE *********'); 15 | await box.put( 16 | '${HiveKeys.homeResponse}_${currentUser!.user.username}', homeResponse); 17 | } 18 | 19 | Future retrieveCachedHomeResponse() async { 20 | final box = 21 | await Hive.openLazyBox(HiveBoxes.homeResponseBox); 22 | return box.get('${HiveKeys.homeResponse}_${currentUser!.user.username}'); 23 | } 24 | 25 | static Future deleteHomeCachedResponse() async { 26 | final box = 27 | await Hive.openLazyBox(HiveBoxes.homeResponseBox); 28 | await box.delete('${HiveKeys.homeResponse}_${currentUser!.user.username}'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/stores/presentation/widgets/stores_shimmer_loading.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:store_ify/core/utils/app_constants.dart'; 4 | import 'package:store_ify/core/widgets/my_sized_box.dart'; 5 | import 'package:store_ify/core/widgets/shimmer_widget.dart'; 6 | import 'package:store_ify/core/widgets/stores_grid_view_shimmer.dart'; 7 | import 'package:store_ify/core/widgets/horizontal_separated_list_view.dart'; 8 | 9 | class StoresShimmerLoading extends StatelessWidget { 10 | const StoresShimmerLoading({super.key}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Column( 15 | children: [ 16 | Container( 17 | height: 25.h, 18 | margin: AppConstants.categoryMargin, 19 | child: HorizontalSeparatedListView( 20 | padding: AppConstants.categoryPadding, 21 | separatorWidget: MySizedBox.width8, 22 | itemBuilder: (_, __) => ShimmerWidget( 23 | height: 25.h, 24 | width: 75.w, 25 | circularRadiusVal: 35, 26 | ), 27 | itemCount: 5, 28 | ), 29 | ), 30 | const Expanded( 31 | child: StoresGridViewShimmer(), 32 | ), 33 | MySizedBox.height16, 34 | ], 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/features/profile/presentation/widgets/update_profile_form.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:store_ify/generated/locale_keys.g.dart'; 4 | import 'package:store_ify/core/widgets/email_text_form_field.dart'; 5 | import 'package:store_ify/core/widgets/my_sized_box.dart'; 6 | import 'package:store_ify/core/widgets/username_text_form_field.dart'; 7 | import 'package:store_ify/features/auth/presentation/widgets/text_field_label.dart'; 8 | import 'package:store_ify/features/profile/presentation/cubits/update_profile/update_profile_cubit.dart'; 9 | 10 | class UpdateProfileForm extends StatelessWidget { 11 | const UpdateProfileForm({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Column( 16 | crossAxisAlignment: CrossAxisAlignment.start, 17 | children: [ 18 | const TextFieldLabel(labelKey: LocaleKeys.email), 19 | EmailTextFormField( 20 | onChanged: (text) => 21 | context.read().onChangeEmail(text), 22 | ), 23 | MySizedBox.height24, 24 | const TextFieldLabel(labelKey: LocaleKeys.username), 25 | UsernameTextFormField( 26 | onChanged: (text) => 27 | context.read().onChangeUsername(text), 28 | ), 29 | ], 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/features/search/data/datasource/search_local_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hive_flutter/hive_flutter.dart'; 3 | import 'package:store_ify/core/helpers/hive_boxes.dart'; 4 | import 'package:store_ify/core/helpers/hive_keys.dart'; 5 | import 'package:store_ify/core/utils/app_constants.dart'; 6 | import 'package:store_ify/features/search/data/models/fetch_search_data_response.dart'; 7 | 8 | class SearchLocalDatasource { 9 | const SearchLocalDatasource(); 10 | 11 | Future cacheSearchData(FetchSearchDataResponse searchData) async { 12 | final box = await Hive.openLazyBox( 13 | HiveBoxes.searchDataBox); 14 | debugPrint('*********** CACHED SEARCH DATA ***********'); 15 | await box.put( 16 | '${HiveKeys.searchData}_${currentUser!.user.username}', searchData); 17 | } 18 | 19 | Future retrieveCachedSearchData() async { 20 | final box = await Hive.openLazyBox( 21 | HiveBoxes.searchDataBox); 22 | return box.get('${HiveKeys.searchData}_${currentUser!.user.username}'); 23 | } 24 | 25 | static Future deleteCachedSearchData() async { 26 | final box = await Hive.openLazyBox( 27 | HiveBoxes.searchDataBox); 28 | await box.delete('${HiveKeys.searchData}_${currentUser!.user.username}'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/stores/presentation/cubits/store_details/store_details_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:store_ify/features/stores/data/models/fetch_store_branches.dart'; 3 | import 'package:store_ify/features/stores/data/models/fetch_store_categories_response.dart'; 4 | import 'package:store_ify/features/stores/data/models/fetch_store_offers_response.dart'; 5 | 6 | part 'store_details_state.freezed.dart'; 7 | 8 | enum StoreDetailsStateStatus { 9 | initial, 10 | fetchStoreBranchesLoading, 11 | fetchStoreBranchesSuccess, 12 | fetchStoreBranchesError, 13 | fetchStoreCategoriesLoading, 14 | fetchStoreCategoriesSuccess, 15 | fetchStoreCategoriesError, 16 | fetchStoreOffersLoading, 17 | fetchStoreOffersSuccess, 18 | fetchStoreOffersError, 19 | updateCurrentDetailsIndex 20 | } 21 | 22 | @freezed 23 | class StoreDetailsState with _$StoreDetailsState { 24 | const factory StoreDetailsState({ 25 | required StoreDetailsStateStatus status, 26 | FetchStoreBranchesResponse? storeBranches, 27 | FetchStoreCategoriesResponse? storeCategories, 28 | FetchStoreOffersResponse? storeOffers, 29 | String? error, 30 | @Default(0) int selectedDetailIndex, 31 | }) = _StoreDetailsState; 32 | 33 | factory StoreDetailsState.initial() => const StoreDetailsState( 34 | status: StoreDetailsStateStatus.initial, 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/checkout/data/models/checkout_response.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'checkout_response.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CheckoutResponse _$CheckoutResponseFromJson(Map json) => 10 | CheckoutResponse( 11 | order: Order.fromJson(json['order'] as Map), 12 | ); 13 | 14 | Map _$CheckoutResponseToJson(CheckoutResponse instance) => 15 | { 16 | 'order': instance.order.toJson(), 17 | }; 18 | 19 | Order _$OrderFromJson(Map json) => Order( 20 | id: (json['id'] as num).toInt(), 21 | userId: (json['user_id'] as num).toInt(), 22 | total: (json['total'] as num).toDouble(), 23 | status: json['status'] as String, 24 | deliveryDate: json['delivery_date'] as String, 25 | deliveryTime: json['delivery_time'] as String, 26 | ); 27 | 28 | Map _$OrderToJson(Order instance) => { 29 | 'id': instance.id, 30 | 'user_id': instance.userId, 31 | 'total': instance.total, 32 | 'status': instance.status, 33 | 'delivery_date': instance.deliveryDate, 34 | 'delivery_time': instance.deliveryTime, 35 | }; 36 | -------------------------------------------------------------------------------- /lib/features/home/data/repos/home_repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:store_ify/core/api/api_result.dart'; 3 | import 'package:store_ify/core/utils/functions/execute_and_handle_errors.dart'; 4 | import 'package:store_ify/features/home/data/api/home_api_service.dart'; 5 | import 'package:store_ify/features/home/data/datasources/home_local_datasource.dart'; 6 | import 'package:store_ify/features/home/data/models/fetch_home_response.dart'; 7 | 8 | class HomeRepo { 9 | final HomeApiService _homeApiService; 10 | final HomeLocalDatasource _localDatasource; 11 | 12 | const HomeRepo(this._homeApiService, this._localDatasource); 13 | 14 | Future> fetchHomeData() async { 15 | final FetchHomeResponse? cachedHomeResponse = 16 | await _localDatasource.retrieveCachedHomeResponse(); 17 | if (cachedHomeResponse == null) { 18 | debugPrint('********** NO CACHED HOME RESPONSE **********'); 19 | return executeAndHandleErrors( 20 | () async { 21 | final homeResponse = await _homeApiService.fetchHomeData(); 22 | await _localDatasource.cacheHomeResponse(homeResponse); 23 | return homeResponse; 24 | }, 25 | ); 26 | } else { 27 | debugPrint('********* FETCHED CACHED HOME RESPONSE *********'); 28 | return ApiResult.success(cachedHomeResponse); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/features/search/data/models/fetch_search_data_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/hive_flutter.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:store_ify/core/helpers/hive_type_ids.dart'; 4 | 5 | part 'fetch_search_data_response.g.dart'; 6 | 7 | @HiveType(typeId: HiveTypeIds.searchData) 8 | @JsonSerializable(explicitToJson: true) 9 | class FetchSearchDataResponse { 10 | @HiveField(0) 11 | final List topCategories; 12 | 13 | @HiveField(1) 14 | final List topStores; 15 | 16 | FetchSearchDataResponse({ 17 | required this.topCategories, 18 | required this.topStores, 19 | }); 20 | 21 | factory FetchSearchDataResponse.fromJson(Map json) => 22 | _$FetchSearchDataResponseFromJson(json); 23 | Map toJson() => _$FetchSearchDataResponseToJson(this); 24 | } 25 | 26 | @HiveType(typeId: HiveTypeIds.searchDataItem) 27 | @JsonSerializable() 28 | class SearchDataItem { 29 | @HiveField(0) 30 | final int id; 31 | @HiveField(1) 32 | final String name; 33 | @HiveField(2) 34 | final String img; 35 | 36 | SearchDataItem({ 37 | required this.id, 38 | required this.name, 39 | required this.img, 40 | }); 41 | 42 | factory SearchDataItem.fromJson(Map json) => 43 | _$SearchDataItemFromJson(json); 44 | Map toJson() => _$SearchDataItemToJson(this); 45 | } 46 | --------------------------------------------------------------------------------