├── features ├── onboarding │ ├── analysis_options.yaml │ ├── lib │ │ ├── onboarding.dart │ │ └── cubit │ │ │ └── on_boarding_cubit.dart │ └── pubspec.yaml ├── settings │ ├── test │ │ └── ui │ │ │ └── settings_test.dart │ ├── analysis_options.yaml │ ├── lib │ │ ├── cubit │ │ │ ├── theme_state.dart │ │ │ └── theme_cubit.dart │ │ ├── di │ │ │ └── di.dart │ │ ├── ui │ │ │ └── components │ │ │ │ ├── pop_up_item.dart │ │ │ │ ├── list_tile.dart │ │ │ │ └── user_avatar.dart │ │ ├── settings.dart │ │ └── bloc │ │ │ ├── settings_state.dart │ │ │ └── settings_event.dart │ ├── .metadata │ └── pubspec.yaml ├── dashboard │ ├── analysis_options.yaml │ ├── lib │ │ └── dashboard.dart │ ├── .metadata │ └── pubspec.yaml ├── product_details │ ├── analysis_options.yaml │ ├── lib │ │ ├── di │ │ │ └── di.dart │ │ ├── bloc │ │ │ ├── details │ │ │ │ ├── details_event.dart │ │ │ │ ├── details_state.dart │ │ │ │ └── details_bloc.dart │ │ │ └── produc_count │ │ │ │ └── product_count_cubit.dart │ │ └── product_details.dart │ ├── .metadata │ └── pubspec.yaml ├── home │ ├── lib │ │ └── src │ │ │ ├── bloc │ │ │ ├── menu │ │ │ │ ├── menu_event.dart │ │ │ │ ├── menu_state.dart │ │ │ │ └── menu_bloc.dart │ │ │ └── home │ │ │ │ ├── home_event.dart │ │ │ │ ├── home_state.dart │ │ │ │ └── home_bloc.dart │ │ │ ├── ui │ │ │ └── components │ │ │ │ ├── sliver_list.dart │ │ │ │ ├── home_shadow.dart │ │ │ │ ├── home_title.dart │ │ │ │ ├── menu_title.dart │ │ │ │ ├── app_bar.dart │ │ │ │ └── search_text_field.dart │ │ │ └── home.dart │ └── pubspec.yaml ├── order │ ├── lib │ │ ├── bloc │ │ │ ├── order_event.dart │ │ │ ├── order_state.dart │ │ │ └── order_bloc.dart │ │ ├── order.dart │ │ └── ui │ │ │ └── components │ │ │ ├── order_date.dart │ │ │ └── order_price.dart │ ├── .metadata │ └── pubspec.yaml ├── admin │ ├── lib │ │ ├── ui │ │ │ └── page │ │ │ │ ├── sales │ │ │ │ └── sales_page.dart │ │ │ │ └── product_count │ │ │ │ └── product_counts_page.dart │ │ ├── bloc │ │ │ ├── users │ │ │ │ └── bloc │ │ │ │ │ ├── users_event.dart │ │ │ │ │ └── users_state.dart │ │ │ └── admin │ │ │ │ ├── admin_event.dart │ │ │ │ ├── admin_state.dart │ │ │ │ └── admin_bloc.dart │ │ └── admin.dart │ ├── .metadata │ └── pubspec.yaml ├── card │ ├── .metadata │ ├── pubspec.yaml │ └── lib │ │ ├── shopping_card.dart │ │ ├── bloc │ │ ├── cart_state.dart │ │ └── cart_event.dart │ │ └── ui │ │ ├── page │ │ └── shopping_card.dart │ │ └── components │ │ └── empty_cart.dart └── auth │ ├── lib │ ├── providers │ │ └── user_provider.dart │ ├── auth.dart │ ├── bloc │ │ ├── auth_state.dart │ │ └── auth_event.dart │ └── components │ │ └── sign_in_form.dart │ └── pubspec.yaml ├── 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 │ │ │ ├── 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 │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── GoogleService-Info.plist │ ├── Base.lproj │ │ └── Main.storyboard │ └── 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 ├── core ├── lib │ ├── enums │ │ ├── hero_tags.dart │ │ ├── user_update_action.dart │ │ ├── weight.dart │ │ ├── currency.dart │ │ ├── locale.dart │ │ ├── firebase.dart │ │ └── duration.dart │ ├── constants │ │ ├── api.dart │ │ ├── connection.dart │ │ └── string_constants.dart │ ├── extensions │ │ ├── string.dart │ │ └── context.dart │ ├── utils │ │ └── typedefs.dart │ ├── exceptions │ │ ├── url_launcher.dart │ │ ├── firebase.dart │ │ ├── server.dart │ │ ├── cache.dart │ │ └── failure.dart │ ├── usecase │ │ └── usecase.dart │ ├── services │ │ ├── connection │ │ │ └── connection.dart │ │ └── url_laucher │ │ │ └── url_laucher.dart │ ├── di │ │ └── di.dart │ └── core.dart └── pubspec.yaml ├── assets ├── images │ ├── user.png │ ├── person.jpg │ ├── splash.png │ ├── app_icon.png │ ├── day_icon.png │ ├── cofix_logo.png │ ├── night_icon.png │ ├── onboarding_1.png │ ├── onboarding_2.png │ ├── onboarding_3.png │ ├── sliver_appbar.jpg │ ├── sliver_appbar1.jpg │ ├── image_placeholder.png │ ├── onBoarding_background.png │ ├── auth_gradient_background.png │ └── profile_gradient_background.png └── fonts │ ├── Poppins-Bold.ttf │ ├── Poppins-Thin.ttf │ ├── Poppins-Black.ttf │ ├── Poppins-Italic.ttf │ ├── Poppins-Light.ttf │ ├── Poppins-Medium.ttf │ ├── Poppins-Regular.ttf │ ├── Poppins-ExtraBold.ttf │ ├── Poppins-SemiBold.ttf │ ├── Poppins-BlackItalic.ttf │ ├── Poppins-BoldItalic.ttf │ ├── Poppins-ExtraLight.ttf │ ├── Poppins-LightItalic.ttf │ ├── Poppins-MediumItalic.ttf │ ├── Poppins-ThinItalic.ttf │ ├── Poppins-SemiBoldItalic.ttf │ ├── Poppins-ExtraBoldItalic.ttf │ └── Poppins-ExtraLightItalic.ttf ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── drawable │ │ │ │ │ ├── background.png │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ ├── background.png │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── launcher_icon.png │ │ │ │ ├── values-v31 │ │ │ │ │ └── styles.xml │ │ │ │ ├── values-night-v31 │ │ │ │ │ └── styles.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── amazon_prime │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── google-services.json ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── domain ├── lib │ ├── repository │ │ ├── settings │ │ │ ├── contacts │ │ │ │ └── contacts_repository.dart │ │ │ ├── theme │ │ │ │ └── theme_repository.dart │ │ │ ├── avatar │ │ │ │ └── user_avatar_repository.dart │ │ │ └── font │ │ │ │ └── font_size_repository.dart │ │ ├── onboarding │ │ │ └── onboarding_repository.dart │ │ ├── product │ │ │ └── product_repository.dart │ │ ├── cart │ │ │ └── cart_repository.dart │ │ ├── order │ │ │ └── order_repository.dart │ │ ├── admin │ │ │ └── admin_repository.dart │ │ └── auth │ │ │ └── auth_repository.dart │ ├── entity │ │ ├── font_size.dart │ │ ├── cart.dart │ │ ├── menu.dart │ │ ├── user_order.dart │ │ ├── product.dart │ │ ├── user.dart │ │ └── page_content.dart │ └── usecase │ │ ├── auth │ │ ├── get_current_user.dart │ │ ├── forgot_password_usecase.dart │ │ ├── log_out_use_case.dart │ │ ├── sign_in_with_google_usecase.dart │ │ ├── sign_in_usecase.dart │ │ └── sign_up_usecase.dart │ │ ├── product │ │ ├── get_products.dart │ │ └── get_product_by_id.dart │ │ ├── cart │ │ ├── get_all_cart_items.dart │ │ ├── add_cart_item.dart │ │ ├── remove_cart_item.dart │ │ └── remove_all_cart_tems.dart │ │ ├── get_menu.dart │ │ ├── order │ │ ├── get_all_orders_usecase.dart │ │ ├── get_orders_per_day.dart │ │ ├── save_order_usecase.dart │ │ └── save_order_remote_usecase.dart │ │ ├── settings │ │ ├── theme │ │ │ ├── get_app_theme_usecase.dart │ │ │ └── save_app_theme_usecase.dart │ │ ├── constacts │ │ │ └── launch_contacts_usecase.dart │ │ ├── avatar │ │ │ └── change_user_avatar_usecase.dart │ │ └── font │ │ │ ├── get_font_usecase.dart │ │ │ └── save_font_usecase.dart │ │ ├── admin │ │ ├── fetch_all_users_per_day_usecase.dart │ │ ├── fetch_all_users_by_registration_date_usecase.dart │ │ └── save_product_usecase.dart │ │ └── onboarding │ │ ├── cache_first_timer_usecase.dart │ │ └── check_if_user_is_first_timer_usecase.dart └── pubspec.yaml ├── core_ui ├── lib │ ├── theme │ │ └── app_theme.dart │ ├── utils │ │ ├── auth_heroes.dart │ │ ├── auth_utils.dart │ │ └── utils.dart │ ├── constants │ │ ├── widget.dart │ │ └── image_path.dart │ └── components │ │ ├── app_bar_item.dart │ │ ├── app_toast.dart │ │ ├── gradient_backgaround.dart │ │ ├── app_refresh_view.dart │ │ ├── app_rating_bar.dart │ │ ├── rounded_button.dart │ │ ├── app_button.dart │ │ ├── app_add_button.dart │ │ ├── app_theme_icon_button.dart │ │ └── cached_network_image.dart └── pubspec.yaml ├── navigation ├── lib │ ├── di │ │ └── di.dart │ └── navigation.dart ├── analysis_options.yaml ├── .metadata └── pubspec.yaml ├── data ├── lib │ ├── data_provider │ │ ├── locale │ │ │ ├── user │ │ │ │ ├── locale_user.dart │ │ │ │ └── user_locale_impl.dart │ │ │ └── locale_data_source.dart │ │ ├── settings │ │ │ ├── settings_remote_data_source.dart │ │ │ └── settings_remote_data_source_impl.dart │ │ ├── remote │ │ │ ├── order │ │ │ │ └── remote_order_data_source_impl.dart │ │ │ ├── remote_data_sourse.dart │ │ │ └── admin │ │ │ │ └── remote_admin_data_source.dart │ │ └── auth │ │ │ └── auth_remote_data_source.dart │ ├── model │ │ ├── font_size.dart │ │ ├── menu.dart │ │ ├── menu.g.dart │ │ ├── order.dart │ │ ├── product.dart │ │ ├── user.g.dart │ │ ├── font_size.g.dart │ │ └── user.dart │ ├── mapper │ │ ├── font_size.dart │ │ ├── menu.dart │ │ ├── order.dart │ │ ├── product.dart │ │ └── user.dart │ └── repository_impl │ │ ├── settings │ │ ├── avatar │ │ │ └── user_avatar_repository.dart │ │ ├── theme │ │ │ └── theme_repository_impl.dart │ │ └── font │ │ │ └── font_repository_impl.dart │ │ ├── cart │ │ └── cart_repository_impl.dart │ │ ├── order │ │ └── order_repository_impl.dart │ │ ├── onboarding │ │ └── on_boarding_repository_impl.dart │ │ ├── admin │ │ └── admin_repository_impl.dart │ │ └── product │ │ └── product_repository_impl.dart └── pubspec.yaml ├── .run └── main.dart.run.xml ├── test ├── .metadata ├── lib │ ├── widget │ │ └── core_ui │ │ │ ├── test_wrapper_widget.dart │ │ │ ├── app_button_test.dart │ │ │ └── app_text_field_test.dart │ ├── test.dart │ └── unit │ │ └── domain │ │ └── usecase │ │ └── auth │ │ ├── log_out_test.dart │ │ ├── sign_in_with_google_test.dart │ │ ├── sign_up_test.dart │ │ └── sign_in_test.dart ├── .gitignore └── pubspec.yaml ├── lib ├── app.dart └── main.dart ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── .gitignore ├── LICENSE ├── pubspec.yaml ├── pub_get_script.sh └── .metadata /features/onboarding/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /features/settings/test/ui/settings_test.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /core/lib/enums/hero_tags.dart: -------------------------------------------------------------------------------- 1 | enum HeroTags { 2 | homeToDetails, 3 | } 4 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /features/settings/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | -------------------------------------------------------------------------------- /assets/images/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/user.png -------------------------------------------------------------------------------- /assets/images/person.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/person.jpg -------------------------------------------------------------------------------- /assets/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/splash.png -------------------------------------------------------------------------------- /assets/images/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/app_icon.png -------------------------------------------------------------------------------- /assets/images/day_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/day_icon.png -------------------------------------------------------------------------------- /assets/fonts/Poppins-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-Thin.ttf -------------------------------------------------------------------------------- /assets/images/cofix_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/cofix_logo.png -------------------------------------------------------------------------------- /assets/images/night_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/night_icon.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /assets/fonts/Poppins-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-Black.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-Italic.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-Light.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-Regular.ttf -------------------------------------------------------------------------------- /assets/images/onboarding_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/onboarding_1.png -------------------------------------------------------------------------------- /assets/images/onboarding_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/onboarding_2.png -------------------------------------------------------------------------------- /assets/images/onboarding_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/onboarding_3.png -------------------------------------------------------------------------------- /assets/images/sliver_appbar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/sliver_appbar.jpg -------------------------------------------------------------------------------- /assets/images/sliver_appbar1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/sliver_appbar1.jpg -------------------------------------------------------------------------------- /assets/fonts/Poppins-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-ExtraBold.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-SemiBold.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-BlackItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-BoldItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-ExtraLight.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-LightItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-MediumItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-ThinItalic.ttf -------------------------------------------------------------------------------- /assets/images/image_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/image_placeholder.png -------------------------------------------------------------------------------- /core/lib/constants/api.dart: -------------------------------------------------------------------------------- 1 | final class ApiConstants { 2 | static const String contactsUrl = 'https://market.yandex.ru/'; 3 | } 4 | -------------------------------------------------------------------------------- /assets/fonts/Poppins-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /assets/images/onBoarding_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/onBoarding_background.png -------------------------------------------------------------------------------- /assets/fonts/Poppins-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/fonts/Poppins-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /assets/images/auth_gradient_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/auth_gradient_background.png -------------------------------------------------------------------------------- /domain/lib/repository/settings/contacts/contacts_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class ConstactsRepository { 2 | Future launchUrl(); 3 | } 4 | -------------------------------------------------------------------------------- /core/lib/enums/user_update_action.dart: -------------------------------------------------------------------------------- 1 | enum UpdateUserAction { 2 | displayName, 3 | email, 4 | password, 5 | bio, 6 | image, 7 | } 8 | -------------------------------------------------------------------------------- /assets/images/profile_gradient_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/assets/images/profile_gradient_background.png -------------------------------------------------------------------------------- /core/lib/enums/weight.dart: -------------------------------------------------------------------------------- 1 | enum Weight { 2 | ml('мл'), 3 | gr('гр'); 4 | 5 | final String value; 6 | 7 | const Weight(this.value); 8 | } 9 | -------------------------------------------------------------------------------- /core_ui/lib/theme/app_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | abstract class AppTheme { 4 | static ThemeData? themeData; 5 | } 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/android/app/src/main/res/drawable/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/android/app/src/main/res/drawable-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /core/lib/enums/currency.dart: -------------------------------------------------------------------------------- 1 | enum Currency { 2 | rubl('₽'), 3 | dollar('\$'); 4 | 5 | final String value; 6 | 7 | const Currency(this.value); 8 | } 9 | -------------------------------------------------------------------------------- /core/lib/enums/locale.dart: -------------------------------------------------------------------------------- 1 | enum LocaleStorage { 2 | theme, 3 | key, 4 | cart, 5 | products, 6 | font, 7 | userAuth, 8 | order, 9 | } 10 | -------------------------------------------------------------------------------- /domain/lib/entity/font_size.dart: -------------------------------------------------------------------------------- 1 | final class FontSizeEntity { 2 | double fontSize; 3 | 4 | FontSizeEntity({ 5 | this.fontSize = 1, 6 | }); 7 | } 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/android/app/src/main/res/mipmap-hdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/android/app/src/main/res/mipmap-mdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /navigation/lib/di/di.dart: -------------------------------------------------------------------------------- 1 | import 'package:navigation/navigation.dart'; 2 | 3 | void initNavigation() { 4 | getIt.registerSingleton(AppRouter()); 5 | } 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /core/lib/enums/firebase.dart: -------------------------------------------------------------------------------- 1 | enum FirebaseEnum { 2 | coffee, 3 | menu, 4 | id, 5 | name, 6 | users, 7 | registrationDate, 8 | orders, 9 | products, 10 | date, 11 | } 12 | -------------------------------------------------------------------------------- /domain/lib/repository/settings/theme/theme_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class ThemeRepository { 2 | Future saveAppTheme(bool isDark); 3 | 4 | Future getAppTheme(String key); 5 | } 6 | -------------------------------------------------------------------------------- /core/lib/extensions/string.dart: -------------------------------------------------------------------------------- 1 | extension NullableString on String? { 2 | String get orNull => ''; 3 | } 4 | 5 | extension StringExtension on String { 6 | static String get orEmpty => ''; 7 | } 8 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAltiyev/amazox_prime/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/AliAltiyev/amazox_prime/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /navigation/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /data/lib/data_provider/locale/user/locale_user.dart: -------------------------------------------------------------------------------- 1 | abstract class UserLocale { 2 | Future initBox(); 3 | 4 | Future saveUserFirstTime(); 5 | 6 | Future checkUserIfExists(); 7 | } 8 | -------------------------------------------------------------------------------- /data/lib/data_provider/settings/settings_remote_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | abstract class SettingsRemoteDataSource { 4 | Future changeAvatar(File imageFile); 5 | } 6 | -------------------------------------------------------------------------------- /features/dashboard/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /features/product_details/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /domain/lib/repository/settings/avatar/user_avatar_repository.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | abstract class UserAvatarRepository { 4 | Future changeUserAvatar({ 5 | required File imageFile, 6 | }); 7 | } 8 | -------------------------------------------------------------------------------- /features/product_details/lib/di/di.dart: -------------------------------------------------------------------------------- 1 | import 'package:product_details/product_details.dart'; 2 | 3 | void initDetails() { 4 | getIt.registerLazySingleton( 5 | () => DetailsBloc(getIt()), 6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /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/app/src/main/kotlin/com/example/amazon_prime/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.amazon_prime 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity : FlutterActivity() { 6 | 7 | 8 | } 9 | -------------------------------------------------------------------------------- /core/lib/utils/typedefs.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/core.dart'; 2 | 3 | typedef ResultFuture = Future>; 4 | typedef ResultStream = Stream>; 5 | typedef DataMap = Map; 6 | -------------------------------------------------------------------------------- /features/settings/lib/cubit/theme_state.dart: -------------------------------------------------------------------------------- 1 | part of 'theme_cubit.dart'; 2 | 3 | @immutable 4 | abstract class ThemeState {} 5 | 6 | final class ThemeInitial extends ThemeState {} 7 | 8 | final class ThemeChanged extends ThemeState {} 9 | -------------------------------------------------------------------------------- /features/home/lib/src/bloc/menu/menu_event.dart: -------------------------------------------------------------------------------- 1 | part of 'menu_bloc.dart'; 2 | 3 | @immutable 4 | abstract class MenuEvent {} 5 | 6 | final class FetchMenuEvent extends MenuEvent {} 7 | 8 | final class ChangeMenuItemSizeEvent extends MenuEvent {} 9 | -------------------------------------------------------------------------------- /domain/lib/repository/onboarding/onboarding_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | abstract class OnBoardingRepository { 4 | ResultFuture cacheFirstTimer(); 5 | 6 | ResultFuture checkIfUserIsFirstTimer(); 7 | } 8 | -------------------------------------------------------------------------------- /domain/lib/repository/settings/font/font_size_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/entity/font_size.dart'; 2 | 3 | abstract class FontSizeRepository { 4 | Future saveFontSize(FontSizeEntity fontSize); 5 | 6 | FontSizeEntity getFontSize(); 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 | -------------------------------------------------------------------------------- /data/lib/data_provider/remote/order/remote_order_data_source_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | abstract class RemoteOrderDataSource { 4 | Future saveOrderToFirebase(UserOrderEntity order); 5 | Future> getOrdersPerDay(); 6 | } 7 | -------------------------------------------------------------------------------- /features/dashboard/lib/dashboard.dart: -------------------------------------------------------------------------------- 1 | library dashboard; 2 | 3 | export 'package:core_ui/constants/string.dart'; 4 | export 'package:dashboard/ui/dashboard_page.dart'; 5 | export 'package:flutter/material.dart'; 6 | export 'package:navigation/navigation.dart'; 7 | -------------------------------------------------------------------------------- /core/lib/constants/connection.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/extensions/string.dart'; 2 | 3 | final class ConnectionConstants { 4 | static const String connectionNotExists = 'Нет подключения к интернету'; 5 | static String connectionExists = StringExtension.orEmpty; 6 | } 7 | -------------------------------------------------------------------------------- /features/order/lib/bloc/order_event.dart: -------------------------------------------------------------------------------- 1 | part of 'order_bloc.dart'; 2 | 3 | @immutable 4 | abstract class OrderEvent extends Equatable {} 5 | 6 | final class FetchAllOrders extends OrderEvent { 7 | @override 8 | List get props => []; 9 | } 10 | -------------------------------------------------------------------------------- /core/lib/exceptions/url_launcher.dart: -------------------------------------------------------------------------------- 1 | final class UrlLauncherException implements Exception { 2 | final String message; 3 | 4 | const UrlLauncherException( 5 | this.message, 6 | ); 7 | 8 | @override 9 | String toString() { 10 | return message; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core_ui/lib/utils/auth_heroes.dart: -------------------------------------------------------------------------------- 1 | class AppHeroTags { 2 | static const String authButton = 'auth_button'; 3 | static const String helperText = 'helper_text'; 4 | static const String redirectText = 'redirect_text'; 5 | static const String homeToDetails = 'homeToDetails'; 6 | } 7 | -------------------------------------------------------------------------------- /features/admin/lib/ui/page/sales/sales_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:admin/admin.dart'; 2 | 3 | class SalesPage extends StatelessWidget { 4 | const SalesPage({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Container(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /data/lib/model/font_size.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | part 'font_size.g.dart'; 4 | 5 | @HiveType(typeId: 2) 6 | final class FontSizeModel { 7 | @HiveField(0) 8 | final double fontSize; 9 | 10 | FontSizeModel({ 11 | required this.fontSize, 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/repository/product/product_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | abstract class ProductRepository { 4 | Future> fetchProducts(); 5 | 6 | Future fetchProductById(int productId); 7 | 8 | Future> fetchMenu(); 9 | } 10 | -------------------------------------------------------------------------------- /features/settings/lib/di/di.dart: -------------------------------------------------------------------------------- 1 | import 'package:settings/settings.dart'; 2 | 3 | void initSettingsBloc() { 4 | getIt.registerLazySingleton( 5 | () => ThemeCubit( 6 | getAppThemeUseCase: getIt(), 7 | saveAppThemeUseCase: getIt(), 8 | ), 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /data/lib/data_provider/remote/remote_data_sourse.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | abstract class RemoteDataSource { 4 | Future> getProducts(); 5 | 6 | Future> getMenu(); 7 | 8 | Future getProductsById(int productId); 9 | } 10 | -------------------------------------------------------------------------------- /.run/main.dart.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /domain/lib/repository/cart/cart_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | abstract class CartRepository { 4 | List getCartAllCartItems(); 5 | Future addCartItem(Product product); 6 | Future removeCartItem(Product product); 7 | Future removeAllCartItems(); 8 | } 9 | -------------------------------------------------------------------------------- /features/admin/lib/ui/page/product_count/product_counts_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:admin/admin.dart'; 2 | 3 | class ProductCountPage extends StatelessWidget { 4 | const ProductCountPage({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Container(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /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:733275854742:ios:343a72426a5d2f9c652fb7", 5 | "FIREBASE_PROJECT_ID": "innofire-ccce6", 6 | "GCM_SENDER_ID": "733275854742" 7 | } -------------------------------------------------------------------------------- /data/lib/data_provider/remote/admin/remote_admin_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | abstract class RemoteAdminDataSource { 4 | Future> getUsersPerDay(); 5 | Future> getUsersByRegistrationDate(); 6 | Future addProduct(ProductModel productModel, File imageFile); 7 | } 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /core/lib/exceptions/firebase.dart: -------------------------------------------------------------------------------- 1 | final class AppFireBaseException implements Exception { 2 | final String _message; 3 | 4 | AppFireBaseException( 5 | String message, 6 | ) : _message = message; 7 | 8 | @override 9 | String toString() { 10 | super.toString(); 11 | return '{$_message}'; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /domain/lib/repository/order/order_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/entity/user_order.dart'; 2 | 3 | abstract class OrderRepository { 4 | Future saveOrderLocale(UserOrder userOrder); 5 | Future saveOrderToFirebase(UserOrder userOrder); 6 | List getAllOrders(); 7 | Future> getOrdersPerDay(); 8 | } 9 | -------------------------------------------------------------------------------- /domain/lib/usecase/auth/get_current_user.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class GetCurrentUserUseCase { 4 | final AuthRepository authRepository; 5 | 6 | GetCurrentUserUseCase({ 7 | required this.authRepository, 8 | }); 9 | 10 | Stream call() => authRepository.getCurrentUser(); 11 | } 12 | -------------------------------------------------------------------------------- /features/admin/lib/bloc/users/bloc/users_event.dart: -------------------------------------------------------------------------------- 1 | part of 'users_bloc.dart'; 2 | 3 | @immutable 4 | sealed class UsersEvent {} 5 | 6 | final class FetchAllUsersPerDayEvent extends UsersEvent {} 7 | 8 | final class CloseBottomSheetEvent extends UsersEvent {} 9 | 10 | final class ShowDailyUserStaticsPressed extends UsersEvent {} 11 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /features/admin/lib/bloc/admin/admin_event.dart: -------------------------------------------------------------------------------- 1 | part of 'admin_bloc.dart'; 2 | 3 | @immutable 4 | sealed class AdminEvent {} 5 | 6 | final class PickImageFromGalleryEvent extends AdminEvent {} 7 | 8 | final class SaveProductEvent extends AdminEvent { 9 | final Product product; 10 | 11 | SaveProductEvent({required this.product}); 12 | } 13 | -------------------------------------------------------------------------------- /features/product_details/lib/bloc/details/details_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:product_details/product_details.dart'; 2 | 3 | @immutable 4 | abstract class DetailsEvent {} 5 | 6 | final class FetchProductEvent extends DetailsEvent { 7 | final int productId; 8 | 9 | FetchProductEvent({ 10 | required this.productId, 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /domain/lib/entity/cart.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | @immutable 4 | final class Cart extends Equatable { 5 | final List cartItems; 6 | 7 | const Cart({ 8 | this.cartItems = const [], 9 | }); 10 | 11 | @override 12 | List get props => [ 13 | cartItems, 14 | ]; 15 | } 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /core/lib/usecase/usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/core.dart'; 2 | 3 | abstract class FutureUsecaseWithoutParams { 4 | const FutureUsecaseWithoutParams(); 5 | 6 | ResultFuture call(); 7 | } 8 | 9 | abstract class FutureUseCaseWithParams { 10 | const FutureUseCaseWithParams(); 11 | 12 | ResultFuture call(Params params); 13 | } 14 | -------------------------------------------------------------------------------- /core/lib/services/connection/connection.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/core.dart'; 2 | 3 | final class Connection { 4 | final InternetConnectionChecker _connection; 5 | 6 | Connection({ 7 | required InternetConnectionChecker connection, 8 | }) : _connection = connection; 9 | 10 | Future isConnected() async => _connection.hasConnection; 11 | } 12 | -------------------------------------------------------------------------------- /test/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 796c8ef79279f9c774545b3771238c3098dbefab 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /domain/lib/usecase/product/get_products.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | class FetchProductsUseCase { 4 | final ProductRepository _repository; 5 | 6 | const FetchProductsUseCase({ 7 | required ProductRepository repository, 8 | }) : _repository = repository; 9 | 10 | Future> call() => _repository.fetchProducts(); 11 | } 12 | -------------------------------------------------------------------------------- /features/card/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 796c8ef79279f9c774545b3771238c3098dbefab 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /features/home/lib/src/bloc/home/home_event.dart: -------------------------------------------------------------------------------- 1 | part of 'home_bloc.dart'; 2 | 3 | @immutable 4 | class ProductsEvent {} 5 | 6 | final class FetchProductsEvent extends ProductsEvent {} 7 | 8 | final class NavigateToProductDetailsScreenEvent extends ProductsEvent { 9 | final int productId; 10 | 11 | NavigateToProductDetailsScreenEvent(this.productId); 12 | } 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /navigation/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 796c8ef79279f9c774545b3771238c3098dbefab 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /features/admin/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 796c8ef79279f9c774545b3771238c3098dbefab 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /features/dashboard/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 796c8ef79279f9c774545b3771238c3098dbefab 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /features/order/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 796c8ef79279f9c774545b3771238c3098dbefab 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /features/settings/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 796c8ef79279f9c774545b3771238c3098dbefab 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /features/product_details/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 796c8ef79279f9c774545b3771238c3098dbefab 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /domain/lib/usecase/cart/get_all_cart_items.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class GetAllCartItemsUseCase { 4 | final CartRepository _cartRepository; 5 | 6 | const GetAllCartItemsUseCase({ 7 | required CartRepository cartRepository, 8 | }) : _cartRepository = cartRepository; 9 | 10 | List call() => _cartRepository.getCartAllCartItems(); 11 | } 12 | -------------------------------------------------------------------------------- /domain/lib/usecase/get_menu.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class FetchMenuItemsUseCase { 4 | final ProductRepository _productsRepository; 5 | 6 | const FetchMenuItemsUseCase({ 7 | required ProductRepository productRepository, 8 | }) : _productsRepository = productRepository; 9 | 10 | Future> call() => _productsRepository.fetchMenu(); 11 | } 12 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /core/lib/exceptions/server.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/core.dart'; 2 | 3 | class ServerException extends Equatable implements Exception { 4 | const ServerException({required this.message, required this.statusCode}); 5 | 6 | final String message; 7 | final String statusCode; 8 | 9 | @override 10 | List get props => [ 11 | message, 12 | statusCode, 13 | ]; 14 | } 15 | -------------------------------------------------------------------------------- /domain/lib/usecase/product/get_product_by_id.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | class FetchProductByIdUseCase { 4 | final ProductRepository _repository; 5 | 6 | const FetchProductByIdUseCase({ 7 | required ProductRepository repository, 8 | }) : _repository = repository; 9 | 10 | Future call(int productId) => 11 | _repository.fetchProductById(productId); 12 | } 13 | -------------------------------------------------------------------------------- /features/onboarding/lib/onboarding.dart: -------------------------------------------------------------------------------- 1 | library onboarding; 2 | 3 | export 'package:core/core.dart'; 4 | export 'package:core_ui/core_ui.dart'; 5 | export 'package:domain/domain.dart'; 6 | export 'package:onboarding/cubit/on_boarding_cubit.dart'; 7 | export 'package:onboarding/onboarding.dart'; 8 | export 'package:onboarding/views/on_boarding_screen.dart'; 9 | export 'package:navigation/navigation.dart'; 10 | -------------------------------------------------------------------------------- /core/lib/enums/duration.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | enum DurationEnum { 4 | low( 5 | Duration( 6 | milliseconds: 100, 7 | ), 8 | ), 9 | normal(Duration( 10 | milliseconds: 300, 11 | )), 12 | high( 13 | Duration( 14 | milliseconds: 500, 15 | ), 16 | ); 17 | 18 | final Duration duration; 19 | 20 | const DurationEnum( 21 | this.duration, 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /data/lib/mapper/font_size.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | abstract class FontSizeMapper { 4 | static FontSizeEntity toEntity(FontSizeModel model) { 5 | return FontSizeEntity( 6 | fontSize: model.fontSize, 7 | ); 8 | } 9 | 10 | static FontSizeModel toModel(FontSizeEntity model) { 11 | return FontSizeModel( 12 | fontSize: model.fontSize, 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /domain/lib/usecase/cart/add_cart_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class AddCartItemUseCase { 4 | final CartRepository _cartRepository; 5 | 6 | const AddCartItemUseCase({ 7 | required CartRepository cartRepository, 8 | }) : _cartRepository = cartRepository; 9 | 10 | Future add(Product product) async { 11 | _cartRepository.addCartItem(product); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/order/get_all_orders_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class GetAllUserOrdersUseCase { 4 | final OrderRepository _orderRepository; 5 | 6 | GetAllUserOrdersUseCase({ 7 | required OrderRepository orderRepository, 8 | }) : _orderRepository = orderRepository; 9 | 10 | List call() { 11 | return _orderRepository.getAllOrders(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/lib/exceptions/cache.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/core.dart'; 2 | 3 | class CacheException extends Equatable implements Exception { 4 | const CacheException({ 5 | required this.message, 6 | this.statusCode = 500, 7 | }); 8 | 9 | final String message; 10 | final int statusCode; 11 | 12 | @override 13 | List get props => [ 14 | message, 15 | statusCode, 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /core_ui/lib/constants/widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | final class WidgetConstants { 4 | static const SliverGridDelegateWithFixedCrossAxisCount 5 | sliverGridDelegateWithFixedCrossAxisCount = 6 | SliverGridDelegateWithFixedCrossAxisCount( 7 | crossAxisCount: 2, 8 | mainAxisSpacing: 10.0, 9 | childAspectRatio: 1 / 2, 10 | crossAxisSpacing: 10.0, 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /domain/lib/usecase/order/get_orders_per_day.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class GetOrdersPerDayUseCase { 4 | final OrderRepository _orderRepository; 5 | 6 | GetOrdersPerDayUseCase({ 7 | required OrderRepository orderRepository, 8 | }) : _orderRepository = orderRepository; 9 | 10 | Future> call() async { 11 | return _orderRepository.getOrdersPerDay(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/cart/remove_cart_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class RemoveCartItemUseCase { 4 | final CartRepository _cartRepository; 5 | 6 | const RemoveCartItemUseCase({ 7 | required CartRepository cartRepository, 8 | }) : _cartRepository = cartRepository; 9 | 10 | Future remove(Product product) async { 11 | _cartRepository.removeCartItem(product); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /features/product_details/lib/bloc/produc_count/product_count_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:product_details/product_details.dart'; 2 | 3 | class ProductCounterCubit extends Cubit { 4 | ProductCounterCubit() : super(1); 5 | 6 | void incrementProductCount() => emit( 7 | state + 1, 8 | ); 9 | 10 | void decrementProductCount() { 11 | if (state > 1) { 12 | emit(state - 1); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /core/lib/extensions/context.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | extension Context on BuildContext { 4 | MediaQueryData get mediaQuery => MediaQuery.of(this); 5 | TextTheme get primaryTextTheme => Theme.of(this).primaryTextTheme; 6 | ColorScheme get colorScheme => Theme.of(this).colorScheme; 7 | double get textScaleFactor => MediaQuery.of(this).textScaleFactor; 8 | ThemeData get theme => Theme.of(this); 9 | } 10 | -------------------------------------------------------------------------------- /domain/lib/entity/menu.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/core.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | @immutable 5 | final class Menu extends Equatable { 6 | final String name; 7 | final String image; 8 | 9 | const Menu({ 10 | required this.name, 11 | required this.image, 12 | }); 13 | 14 | @override 15 | List get props => [ 16 | image, 17 | name, 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /domain/lib/usecase/auth/forgot_password_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | class ForgotPasswordUseCase extends FutureUseCaseWithParams { 4 | final AuthRepository _repository; 5 | 6 | const ForgotPasswordUseCase( 7 | AuthRepository repository, 8 | ) : _repository = repository; 9 | 10 | @override 11 | ResultFuture call(String params) => _repository.forgotPassword(params); 12 | } 13 | -------------------------------------------------------------------------------- /domain/lib/usecase/settings/theme/get_app_theme_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/settings/theme/theme_repository.dart'; 2 | 3 | final class GetAppThemeUseCase { 4 | final ThemeRepository _themeRepository; 5 | 6 | GetAppThemeUseCase({ 7 | required ThemeRepository themeRepository, 8 | }) : _themeRepository = themeRepository; 9 | 10 | Future call(String key) => _themeRepository.getAppTheme(key); 11 | } 12 | -------------------------------------------------------------------------------- /domain/lib/repository/admin/admin_repository.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:domain/domain.dart'; 4 | 5 | abstract class AdminRepository { 6 | Future> getUsersPerDay(); 7 | Future deleteUser(); 8 | Future deleteMultipleUsers(); 9 | Future> getUsersByRegistrationDate(); 10 | Future saveProductToFirebase( 11 | Product product, 12 | File imageFile, 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /core_ui/lib/components/app_bar_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | class AppBarItem { 4 | final Widget icon; 5 | final Widget? activeIcon; 6 | final Widget title; 7 | final Color? selectedColor; 8 | final Color? unselectedColor; 9 | 10 | AppBarItem({ 11 | required this.icon, 12 | required this.title, 13 | this.selectedColor, 14 | this.unselectedColor, 15 | this.activeIcon, 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /domain/lib/usecase/cart/remove_all_cart_tems.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/cart/cart_repository.dart'; 2 | 3 | final class RemoveAllCartItemsUseCase { 4 | final CartRepository _cartRepository; 5 | 6 | const RemoveAllCartItemsUseCase({ 7 | required CartRepository cartRepository, 8 | }) : _cartRepository = cartRepository; 9 | 10 | Future call() async { 11 | _cartRepository.removeAllCartItems(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/order/save_order_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class SaveUserOrderUseCase { 4 | final OrderRepository _orderRepository; 5 | 6 | SaveUserOrderUseCase({ 7 | required OrderRepository orderRepository, 8 | }) : _orderRepository = orderRepository; 9 | 10 | Future call({required UserOrder order}) async { 11 | return _orderRepository.saveOrderLocale(order); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/settings/constacts/launch_contacts_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class LaunchContactsUseCase { 4 | final ConstactsRepository _contactsRepository; 5 | 6 | const LaunchContactsUseCase( 7 | ConstactsRepository constactsRepository, 8 | ) : _contactsRepository = constactsRepository; 9 | 10 | Future call() async { 11 | await _contactsRepository.launchUrl(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/settings/theme/save_app_theme_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/settings/theme/theme_repository.dart'; 2 | 3 | final class SaveAppThemeUseCase { 4 | final ThemeRepository _themeRepository; 5 | 6 | SaveAppThemeUseCase({ 7 | required ThemeRepository themeRepository, 8 | }) : _themeRepository = themeRepository; 9 | 10 | Future call(bool isDark) => _themeRepository.saveAppTheme(isDark); 11 | } 12 | -------------------------------------------------------------------------------- /data/lib/mapper/menu.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/model/menu.dart'; 2 | import 'package:domain/domain.dart'; 3 | 4 | abstract class MenuMapper { 5 | static MenuModel toModel(Menu model) { 6 | return MenuModel( 7 | name: model.name, 8 | image: model.image, 9 | ); 10 | } 11 | 12 | static Menu toEntity(MenuModel model) { 13 | return Menu( 14 | name: model.name, 15 | image: model.image, 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/lib/services/url_laucher/url_laucher.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/core.dart'; 2 | 3 | final class UrlLauncher { 4 | Future launch(String url) async { 5 | try { 6 | final Uri uri = Uri.parse(url); 7 | 8 | if (!await launchUrl( 9 | uri, 10 | )) { 11 | throw UrlLauncherException( 12 | '${StringConstants.urlLauncherException} $url', 13 | ); 14 | } 15 | } catch (_) {} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /domain/lib/usecase/admin/fetch_all_users_per_day_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class FetchAllUsersPerDayUseCase { 4 | final AdminRepository _adminRepository; 5 | 6 | const FetchAllUsersPerDayUseCase({ 7 | required AdminRepository adminRepository, 8 | }) : _adminRepository = adminRepository; 9 | 10 | Future> call() async { 11 | return await _adminRepository.getUsersPerDay(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/onboarding/cache_first_timer_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | class CacheFirstTimerUseCase extends FutureUsecaseWithoutParams { 4 | final OnBoardingRepository _repository; 5 | 6 | const CacheFirstTimerUseCase({ 7 | required OnBoardingRepository repository, 8 | }) : _repository = repository; 9 | 10 | @override 11 | ResultFuture call() async => _repository.cacheFirstTimer(); 12 | } 13 | -------------------------------------------------------------------------------- /domain/lib/usecase/order/save_order_remote_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class SaveOrderRemoteUseCase { 4 | final OrderRepository _orderRepository; 5 | 6 | SaveOrderRemoteUseCase({ 7 | required OrderRepository orderRepository, 8 | }) : _orderRepository = orderRepository; 9 | 10 | Future call({required UserOrder order}) async { 11 | return _orderRepository.saveOrderToFirebase(order); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: domain 2 | description: A new Flutter package project. 3 | version: 0.0.1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: '>=3.0.0 <4.0.0' 8 | flutter: '>=1.17.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | core: 14 | path: ../core 15 | core_ui: 16 | path: ../core_ui 17 | 18 | dev_dependencies: 19 | flutter_lints: ^2.0.0 20 | flutter_test: 21 | sdk: flutter 22 | 23 | flutter: null 24 | -------------------------------------------------------------------------------- /test/lib/widget/core_ui/test_wrapper_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:testing/test.dart'; 2 | 3 | class TestWrapper extends StatelessWidget { 4 | final Widget _widget; 5 | const TestWrapper({ 6 | required Widget widget, 7 | super.key, 8 | }) : _widget = widget; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return MaterialApp( 13 | home: Scaffold( 14 | body: _widget, 15 | ), 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "background.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /core_ui/lib/components/app_toast.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | abstract class AppToast { 4 | static Future showToast() { 5 | return Fluttertoast.showToast( 6 | msg: ConnectionConstants.connectionNotExists, 7 | backgroundColor: ApplicationColors.red, 8 | fontSize: FontSize.s18, 9 | gravity: ToastGravity.TOP, 10 | textColor: ApplicationColors.white, 11 | toastLength: Toast.LENGTH_LONG, 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /features/dashboard/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dashboard 2 | description: Application dashbord layer. 3 | version: 0.0.1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: '>=3.0.5 <4.0.0' 8 | flutter: '>=1.17.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | navigation: 14 | path: ../../navigation/ 15 | core_ui: 16 | path: ../../core_ui/ 17 | 18 | dev_dependencies: 19 | flutter_test: 20 | sdk: flutter 21 | flutter_lints: ^2.0.0 22 | 23 | flutter: 24 | -------------------------------------------------------------------------------- /domain/lib/usecase/onboarding/check_if_user_is_first_timer_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | class CheckIfUserIsFirstTimerUseCase extends FutureUsecaseWithoutParams { 4 | final OnBoardingRepository _repository; 5 | 6 | const CheckIfUserIsFirstTimerUseCase({ 7 | required OnBoardingRepository repository, 8 | }) : _repository = repository; 9 | 10 | @override 11 | ResultFuture call() async => _repository.checkIfUserIsFirstTimer(); 12 | } 13 | -------------------------------------------------------------------------------- /domain/lib/usecase/settings/avatar/change_user_avatar_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:domain/domain.dart'; 4 | 5 | final class ChangeUserAvatarUserCase { 6 | final UserAvatarRepository userAvatarRepository; 7 | 8 | ChangeUserAvatarUserCase({ 9 | required this.userAvatarRepository, 10 | }); 11 | 12 | Future call({ 13 | required File imageFile, 14 | }) { 15 | return userAvatarRepository.changeUserAvatar(imageFile: imageFile); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /features/auth/lib/providers/user_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:auth/auth.dart'; 2 | 3 | class UserProvider extends ChangeNotifier { 4 | UserEntity? _user; 5 | 6 | UserEntity? get user => _user; 7 | 8 | void initUser(UserEntity? user) { 9 | if (_user != user) { 10 | _user = user; 11 | notifyListeners(); 12 | } 13 | } 14 | 15 | set user(UserEntity? user) { 16 | if (_user != user) { 17 | _user = user; 18 | notifyListeners(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /domain/lib/usecase/admin/fetch_all_users_by_registration_date_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | final class FetchAllUserByRegistrationDateUseCase { 4 | final AdminRepository _adminRepository; 5 | 6 | const FetchAllUserByRegistrationDateUseCase({ 7 | required AdminRepository adminRepository, 8 | }) : _adminRepository = adminRepository; 9 | 10 | Future> call() async { 11 | return await _adminRepository.getUsersByRegistrationDate(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /features/card/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: card 2 | description: Application Shopping card layer 3 | version: 0.0.1 4 | publish_to: none 5 | environment: 6 | sdk: '>=3.0.5 <4.0.0' 7 | flutter: '>=1.17.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | core: 13 | path: ../../core 14 | core_ui: 15 | path: ../../core_ui 16 | domain: 17 | path: ../../domain 18 | 19 | dev_dependencies: 20 | flutter_test: 21 | sdk: flutter 22 | flutter_lints: ^2.0.0 23 | 24 | flutter: 25 | -------------------------------------------------------------------------------- /features/home/lib/src/bloc/menu/menu_state.dart: -------------------------------------------------------------------------------- 1 | part of 'menu_bloc.dart'; 2 | 3 | final class MenuState { 4 | List menu; 5 | bool isMenuAnimated; 6 | 7 | MenuState({ 8 | required this.menu, 9 | this.isMenuAnimated = false, 10 | }); 11 | 12 | MenuState copyWith({ 13 | List? menu, 14 | bool? isMenuAnimated, 15 | }) { 16 | return MenuState( 17 | menu: menu ?? this.menu, 18 | isMenuAnimated: isMenuAnimated ?? this.isMenuAnimated, 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/app.dart: -------------------------------------------------------------------------------- 1 | export 'package:amazon_prime/src/app/cofix.dart'; 2 | export 'package:card/shopping_card.dart'; 3 | export 'package:core/core.dart'; 4 | export 'package:core/di/firebase_options.dart'; 5 | export 'package:core_ui/core_ui.dart'; 6 | export 'package:flutter/material.dart'; 7 | export 'package:home/src/home.dart'; 8 | export 'package:navigation/navigation.dart'; 9 | export 'package:order/order.dart'; 10 | export 'package:product_details/product_details.dart'; 11 | export 'package:settings/settings.dart'; 12 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /domain/lib/usecase/settings/font/get_font_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/entity/font_size.dart'; 2 | import 'package:domain/repository/settings/font/font_size_repository.dart'; 3 | 4 | final class GetFontSizeUseCase { 5 | final FontSizeRepository _fontSizeRepository; 6 | 7 | const GetFontSizeUseCase({ 8 | required FontSizeRepository fontSizeRepository, 9 | }) : _fontSizeRepository = fontSizeRepository; 10 | 11 | FontSizeEntity call() { 12 | return _fontSizeRepository.getFontSize(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/lib/constants/string_constants.dart: -------------------------------------------------------------------------------- 1 | final class StringConstants { 2 | static const String stateError = 'Home State Error'; 3 | static const String fireBaseDocsError = 'docs is empty'; 4 | static const String urlLauncherException = 'Can not open this '; 5 | static const String error = 'Error Occurred'; 6 | static const String code_500 = '500'; 7 | static const String tryLater = 'Please try again later'; 8 | static const String admin = 'admin@gmail.com'; 9 | static const String adminPassword = '123456'; 10 | } 11 | -------------------------------------------------------------------------------- /data/lib/repository_impl/settings/avatar/user_avatar_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | final class UserAvatarRepositoryImpl implements UserAvatarRepository { 4 | final SettingsRemoteDataSource settingsRemoteDataSource; 5 | 6 | UserAvatarRepositoryImpl({ 7 | required this.settingsRemoteDataSource, 8 | }); 9 | 10 | @override 11 | Future changeUserAvatar({ 12 | required File imageFile, 13 | }) { 14 | return settingsRemoteDataSource.changeAvatar(imageFile); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core_ui/lib/utils/auth_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AuthUtils { 4 | static Widget buildShuttle( 5 | BuildContext context, 6 | Animation animation, 7 | HeroFlightDirection flightDirection, 8 | BuildContext fromHeroContext, 9 | BuildContext toHeroContext, 10 | ) { 11 | final TextStyle toText = DefaultTextStyle.of(toHeroContext).style; 12 | return DefaultTextStyle( 13 | style: toText, 14 | child: toHeroContext.widget, 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /data/lib/model/menu.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | part 'menu.g.dart'; 4 | 5 | @JsonSerializable() 6 | final class MenuModel { 7 | final String name; 8 | final String image; 9 | 10 | MenuModel({ 11 | required this.name, 12 | required this.image, 13 | }); 14 | 15 | factory MenuModel.fromJson(Map json) { 16 | return _$MenuModelFromJson(json); 17 | } 18 | 19 | Map toJson(MenuModel menuModel) { 20 | return _$MenuModelToJson(menuModel); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /features/order/lib/order.dart: -------------------------------------------------------------------------------- 1 | library order; 2 | 3 | export 'package:card/shopping_card.dart'; 4 | export 'package:core/constants/string_constants.dart'; 5 | export 'package:core/core.dart'; 6 | export 'package:core_ui/core_ui.dart'; 7 | export 'package:domain/domain.dart'; 8 | export 'package:flutter/material.dart'; 9 | export 'package:order/bloc/order_bloc.dart'; 10 | export 'package:order/ui/components/order_date.dart'; 11 | export 'package:order/ui/components/order_price.dart'; 12 | export 'package:order/ui/page/order_history.dart'; 13 | -------------------------------------------------------------------------------- /features/order/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: order 2 | description: Application order layer 3 | version: 0.0.1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: '>=3.0.5 <4.0.0' 8 | flutter: '>=1.17.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | core_ui: 14 | path: ../../core_ui 15 | core: 16 | path: ../../core 17 | domain: 18 | path: ../../domain 19 | card: 20 | path: ../../features/card/ 21 | dev_dependencies: 22 | flutter_test: 23 | sdk: flutter 24 | flutter_lints: ^2.0.0 25 | flutter: 26 | -------------------------------------------------------------------------------- /domain/lib/usecase/auth/log_out_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | class LogOutUseCase extends FutureUseCaseWithParams { 4 | final AuthRepository _repository; 5 | 6 | const LogOutUseCase( 7 | AuthRepository repository, 8 | ) : _repository = repository; 9 | @override 10 | ResultFuture call(LogOutUseCaseParams params) => _repository.logOut(); 11 | } 12 | 13 | class LogOutUseCaseParams extends Equatable { 14 | @override 15 | List get props => []; 16 | } 17 | -------------------------------------------------------------------------------- /features/admin/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: admin 2 | description: feature admin panel 3 | version: 0.0.1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: '>=3.0.5 <4.0.0' 8 | flutter: '>=1.17.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | core_ui: 14 | path: ../../core_ui 15 | core: 16 | path: ../../core 17 | domain: 18 | path: ../../domain 19 | navigation: 20 | path: ../../navigation 21 | 22 | dev_dependencies: 23 | flutter_test: 24 | sdk: flutter 25 | flutter_lints: ^2.0.0 26 | 27 | flutter: 28 | -------------------------------------------------------------------------------- /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 | "filename" : "LaunchImage@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "LaunchImage@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /domain/lib/usecase/admin/save_product_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:domain/domain.dart'; 4 | 5 | final class SaveProductUseCase { 6 | final AdminRepository _adminRepository; 7 | 8 | SaveProductUseCase({ 9 | required AdminRepository adminRepository, 10 | }) : _adminRepository = adminRepository; 11 | 12 | Future call( 13 | Product product, 14 | File imageFile, 15 | ) async { 16 | return _adminRepository.saveProductToFirebase( 17 | product, 18 | imageFile, 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /features/auth/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: auth 2 | description: auth module. 3 | version: 0.0.1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: '>=3.0.5 <4.0.0' 8 | flutter: ">=1.17.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | core_ui: 14 | path: ../../core_ui 15 | core: 16 | path: ../../core 17 | domain: 18 | path: ../../domain 19 | navigation: 20 | path: ../../navigation 21 | 22 | dev_dependencies: 23 | flutter_test: 24 | sdk: flutter 25 | flutter_lints: ^2.0.0 26 | 27 | 28 | flutter: 29 | 30 | -------------------------------------------------------------------------------- /features/onboarding/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: onboarding 2 | description: onboarding layer. 3 | version: 0.0.1 4 | publish_to: none 5 | environment: 6 | sdk: '>=3.0.5 <4.0.0' 7 | flutter: '>=1.17.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | core_ui: 13 | path: ../../core_ui 14 | core: 15 | path: ../../core 16 | domain: 17 | path: ../../domain 18 | navigation: 19 | path: ../../navigation 20 | 21 | dev_dependencies: 22 | flutter_test: 23 | sdk: flutter 24 | flutter_lints: ^2.0.0 25 | 26 | flutter: 27 | -------------------------------------------------------------------------------- /data/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: data 2 | description: data module. 3 | version: 0.0.1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: '>=3.0.0 <4.0.0' 8 | flutter: '>=1.17.0' 9 | 10 | dependencies: 11 | #base 12 | json_annotation: ^4.8.1 13 | 14 | flutter: 15 | sdk: flutter 16 | domain: 17 | path: ../domain 18 | core: 19 | path: ../core 20 | 21 | dev_dependencies: 22 | flutter_test: 23 | sdk: flutter 24 | flutter_lints: ^2.0.0 25 | json_serializable: ^6.7.0 26 | build_runner: ^2.4.5 27 | hive_generator: ^2.0.0 28 | 29 | flutter: 30 | -------------------------------------------------------------------------------- /domain/lib/usecase/settings/font/save_font_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/entity/font_size.dart'; 2 | import 'package:domain/repository/settings/font/font_size_repository.dart'; 3 | 4 | final class SaveFontSizeUseCase { 5 | final FontSizeRepository _fontSizeRepository; 6 | 7 | const SaveFontSizeUseCase({ 8 | required FontSizeRepository fontSizeRepository, 9 | }) : _fontSizeRepository = fontSizeRepository; 10 | 11 | Future call({required FontSizeEntity fontSize}) { 12 | return _fontSizeRepository.saveFontSize(fontSize); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /features/product_details/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: product_details 2 | description: App product details layer 3 | version: 0.0.1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: '>=3.0.5 <4.0.0' 8 | flutter: '>=1.17.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | navigation: 14 | path: ../../navigation/ 15 | domain: 16 | path: ../../domain/ 17 | core_ui: 18 | path: ../../core_ui 19 | core: 20 | path: ../../core 21 | 22 | dev_dependencies: 23 | flutter_test: 24 | sdk: flutter 25 | flutter_lints: ^2.0.0 26 | 27 | flutter: 28 | -------------------------------------------------------------------------------- /domain/lib/entity/user_order.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | @immutable 4 | final class UserOrder extends Equatable { 5 | final String id; 6 | final List products; 7 | final String dateTime; 8 | final double price; 9 | 10 | const UserOrder({ 11 | required this.id, 12 | required this.dateTime, 13 | required this.products, 14 | required this.price, 15 | }); 16 | 17 | @override 18 | List get props => [ 19 | id, 20 | products, 21 | dateTime, 22 | price, 23 | ]; 24 | } 25 | -------------------------------------------------------------------------------- /features/order/lib/ui/components/order_date.dart: -------------------------------------------------------------------------------- 1 | import 'package:order/order.dart'; 2 | 3 | class OrderDate extends StatelessWidget { 4 | const OrderDate({ 5 | super.key, 6 | required this.order, 7 | }); 8 | 9 | final UserOrder order; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Column( 14 | children: [ 15 | Text( 16 | StringConstant.date, 17 | style: AppFonts.bold14, 18 | ), 19 | Text( 20 | order.dateTime, 21 | ), 22 | ], 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /features/settings/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: settings 2 | description: Application settings layer. 3 | version: 0.0.1 4 | publish_to: none 5 | environment: 6 | sdk: '>=3.0.5 <4.0.0' 7 | flutter: '>=1.17.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | navigation: 13 | path: ../../navigation/ 14 | domain: 15 | path: ../../domain/ 16 | core_ui: 17 | path: ../../core_ui 18 | core: 19 | path: ../../core 20 | auth: 21 | path: ../../features/auth/ 22 | dev_dependencies: 23 | flutter_test: 24 | sdk: flutter 25 | flutter_lints: ^2.0.0 26 | 27 | flutter: 28 | -------------------------------------------------------------------------------- /core/lib/di/di.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/core.dart'; 2 | 3 | final GetIt getIt = GetIt.instance; 4 | 5 | Future initAppModule() async { 6 | final FirebaseFirestore fireStore = FirebaseFirestore.instance; 7 | getIt.registerLazySingleton(() => fireStore); 8 | getIt.registerLazySingleton( 9 | UrlLauncher.new, 10 | ); 11 | getIt.registerLazySingleton( 12 | InternetConnectionChecker.new); 13 | 14 | getIt.registerLazySingleton( 15 | () => Connection(connection: getIt()), 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /features/admin/lib/bloc/admin/admin_state.dart: -------------------------------------------------------------------------------- 1 | part of 'admin_bloc.dart'; 2 | 3 | @immutable 4 | sealed class AdminState {} 5 | 6 | final class AdminInitial extends AdminState {} 7 | 8 | final class ImagePickedFromGalleryState extends AdminState { 9 | final String imageFromGallery; 10 | 11 | ImagePickedFromGalleryState({ 12 | required this.imageFromGallery, 13 | }); 14 | } 15 | 16 | final class SavedProductState extends AdminState {} 17 | 18 | final class AdminFailedState extends AdminState { 19 | final String errorMessage; 20 | 21 | AdminFailedState({required this.errorMessage}); 22 | } 23 | -------------------------------------------------------------------------------- /features/auth/lib/auth.dart: -------------------------------------------------------------------------------- 1 | library auth; 2 | 3 | export 'package:auth/auth.dart'; 4 | export 'package:auth/bloc/auth_bloc.dart'; 5 | export 'package:auth/components/sign_in_button.dart'; 6 | export 'package:auth/components/sign_in_form.dart'; 7 | export 'package:auth/page/sign_in_screen.dart'; 8 | export 'package:auth/page/sign_up_screen.dart'; 9 | export 'package:auth/providers/user_provider.dart'; 10 | export 'package:core/core.dart'; 11 | export 'package:core_ui/core_ui.dart'; 12 | export 'package:domain/domain.dart'; 13 | export 'package:flutter/material.dart'; 14 | export 'package:navigation/navigation.dart'; 15 | -------------------------------------------------------------------------------- /features/card/lib/shopping_card.dart: -------------------------------------------------------------------------------- 1 | library cart; 2 | 3 | export 'package:card/bloc/cart_bloc.dart'; 4 | export 'package:card/ui/components/cart_body.dart'; 5 | export 'package:card/ui/components/cart_list_item.dart'; 6 | export 'package:card/ui/components/cart_sublist.dart'; 7 | export 'package:card/ui/components/cart_total_price.dart'; 8 | export 'package:card/ui/components/empty_cart.dart'; 9 | export 'package:card/ui/page/shopping_card.dart'; 10 | export 'package:core/core.dart'; 11 | export 'package:core_ui/core_ui.dart'; 12 | export 'package:domain/domain.dart'; 13 | export 'package:flutter/material.dart'; 14 | -------------------------------------------------------------------------------- /data/lib/repository_impl/settings/theme/theme_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | final class ThemeRepositoryImpl extends ThemeRepository { 4 | final LocaleDataSource _localeDataSource; 5 | 6 | ThemeRepositoryImpl({ 7 | required LocaleDataSource localeDataSource, 8 | }) : _localeDataSource = localeDataSource; 9 | 10 | @override 11 | Future saveAppTheme(bool isDark) => _localeDataSource.saveAppTheme( 12 | isDark, 13 | ); 14 | 15 | @override 16 | Future getAppTheme(String key) => _localeDataSource.getAppTheme( 17 | key, 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /features/home/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: home 2 | description: Home screen module. 3 | version: 0.0.1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: '>=3.0.0 <4.0.0' 8 | flutter: '>=1.17.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | domain: 14 | path: ../../domain/ 15 | core: 16 | path: ../../core/ 17 | core_ui: 18 | path: ../../core_ui/ 19 | navigation: 20 | path: ../../navigation/ 21 | product_details: 22 | path: ../../features./product_details 23 | 24 | dev_dependencies: 25 | flutter_test: 26 | sdk: flutter 27 | flutter_lints: ^2.0.0 28 | 29 | flutter: 30 | -------------------------------------------------------------------------------- /data/lib/data_provider/auth/auth_remote_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | abstract class AuthRemoteDataSource { 4 | const AuthRemoteDataSource(); 5 | 6 | Future signInWithGoogle(); 7 | 8 | Future logOut(); 9 | 10 | Future forgotPassword(String email); 11 | 12 | Future signIn({ 13 | required String email, 14 | required String password, 15 | }); 16 | 17 | Future signUp({ 18 | required String email, 19 | required String fullName, 20 | required String password, 21 | }); 22 | 23 | Stream getCurrentUser(); 24 | } 25 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:amazon_prime/app.dart'; 2 | import 'package:data/data.dart'; 3 | 4 | Future main() async { 5 | WidgetsFlutterBinding.ensureInitialized(); 6 | await Firebase.initializeApp( 7 | options: DefaultFirebaseOptions.currentPlatform, 8 | ); 9 | await initAppModule(); 10 | await initDataLayer(); 11 | initNavigation(); 12 | initSettingsBloc(); 13 | await _initHive(); 14 | runApp(Application()); 15 | } 16 | 17 | Future _initHive() async { 18 | await Hive.initFlutter(); 19 | await getIt().initBox(); 20 | await getIt().initBox(); 21 | } 22 | -------------------------------------------------------------------------------- /domain/lib/repository/auth/auth_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | abstract class AuthRepository { 4 | const AuthRepository(); 5 | 6 | Stream getCurrentUser(); 7 | 8 | ResultFuture signInWithGoogle(); 9 | 10 | ResultFuture signIn({ 11 | required String email, 12 | required String password, 13 | }); 14 | 15 | ResultFuture signUp({ 16 | required String email, 17 | required String fullName, 18 | required String password, 19 | }); 20 | 21 | ResultFuture forgotPassword(String email); 22 | 23 | ResultFuture logOut(); 24 | } 25 | -------------------------------------------------------------------------------- /features/order/lib/bloc/order_state.dart: -------------------------------------------------------------------------------- 1 | part of 'order_bloc.dart'; 2 | 3 | @immutable 4 | abstract class OrderState extends Equatable {} 5 | 6 | final class OrdersLoading extends OrderState { 7 | @override 8 | List get props => []; 9 | } 10 | 11 | final class OrdersLoaded extends OrderState { 12 | final List orders; 13 | 14 | OrdersLoaded({required this.orders}); 15 | 16 | @override 17 | List get props => [ 18 | orders, 19 | ]; 20 | } 21 | 22 | final class OrdersFailure extends OrderState { 23 | @override 24 | List get props => []; 25 | } 26 | -------------------------------------------------------------------------------- /features/order/lib/ui/components/order_price.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/enums/currency.dart'; 2 | import 'package:order/order.dart'; 3 | 4 | class OrderPrice extends StatelessWidget { 5 | const OrderPrice({ 6 | required this.order, 7 | super.key, 8 | }); 9 | 10 | final UserOrder order; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Column( 15 | children: [ 16 | Text( 17 | StringConstant.total, 18 | style: AppFonts.bold14, 19 | ), 20 | Text('${order.price.toString()} ${Currency.rubl.name}') 21 | ], 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /data/lib/model/menu.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'menu.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | MenuModel _$MenuModelFromJson(Map json) => MenuModel( 10 | name: json['name'] as String, 11 | image: json['image'] as String, 12 | ); 13 | 14 | Map _$MenuModelToJson(MenuModel instance) => { 15 | 'name': instance.name, 16 | 'image': instance.image, 17 | }; 18 | -------------------------------------------------------------------------------- /features/settings/lib/ui/components/pop_up_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:settings/settings.dart'; 2 | 3 | class PopupItem extends StatelessWidget { 4 | 5 | final String title; 6 | final Widget icon; 7 | 8 | const PopupItem({ 9 | required this.title, 10 | required this.icon, 11 | super.key, 12 | }); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Row( 17 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 18 | children: [ 19 | Text( 20 | title, 21 | style: AppFonts.bold14, 22 | ), 23 | icon, 24 | ], 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /domain/lib/usecase/auth/sign_in_with_google_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | class SignInWithGoogleUseCase 4 | extends FutureUseCaseWithParams { 5 | final AuthRepository _repository; 6 | 7 | const SignInWithGoogleUseCase( 8 | AuthRepository repository, 9 | ) : _repository = repository; 10 | 11 | @override 12 | ResultFuture call(SignInWithGoogleParams params) => 13 | _repository.signInWithGoogle(); 14 | } 15 | 16 | class SignInWithGoogleParams extends Equatable { 17 | const SignInWithGoogleParams(); 18 | 19 | @override 20 | List get props => []; 21 | } 22 | -------------------------------------------------------------------------------- /test/.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 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /features/product_details/lib/product_details.dart: -------------------------------------------------------------------------------- 1 | library product_details; 2 | 3 | export 'package:core/core.dart'; 4 | export 'package:core_ui/core_ui.dart'; 5 | export 'package:flutter/material.dart'; 6 | export 'package:navigation/navigation.dart'; 7 | export 'package:product_details/bloc/details/details_bloc.dart'; 8 | export 'package:product_details/bloc/details/details_event.dart'; 9 | export 'package:product_details/bloc/details/details_state.dart'; 10 | export 'package:product_details/components/app_bar.dart'; 11 | export 'package:product_details/components/sliver_list.dart'; 12 | export 'package:product_details/product_details.dart'; 13 | export 'package:product_details/ui/product_details_page.dart'; 14 | -------------------------------------------------------------------------------- /features/settings/lib/settings.dart: -------------------------------------------------------------------------------- 1 | library settings; 2 | 3 | export 'package:core/core.dart'; 4 | export 'package:core/extensions/string.dart'; 5 | export 'package:core_ui/core_ui.dart'; 6 | export 'package:domain/domain.dart'; 7 | export 'package:flutter/material.dart'; 8 | export 'package:settings/bloc/settings_bloc.dart'; 9 | export 'package:settings/cubit/theme_cubit.dart'; 10 | export 'package:settings/di/di.dart'; 11 | export 'package:settings/settings.dart'; 12 | export 'package:settings/ui/components/list_tile.dart'; 13 | export 'package:settings/ui/components/pop_up_item.dart'; 14 | export 'package:settings/ui/components/user_avatar.dart'; 15 | export 'package:settings/ui/page/settings_page.dart'; 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /navigation/lib/navigation.dart: -------------------------------------------------------------------------------- 1 | library navigation; 2 | 3 | export 'dart:convert'; 4 | 5 | export 'package:admin/admin.dart'; 6 | export 'package:auth/auth.dart'; 7 | export 'package:auto_route/annotations.dart'; 8 | export 'package:auto_route/auto_route.dart'; 9 | export 'package:card/shopping_card.dart'; 10 | export 'package:core/core.dart'; 11 | export 'package:dashboard/dashboard.dart'; 12 | export 'package:dashboard/ui/dashboard_page.dart'; 13 | export 'package:home/src/home.dart'; 14 | export 'package:navigation/di/di.dart'; 15 | export 'package:onboarding/onboarding.dart'; 16 | export 'package:order/order.dart'; 17 | export 'package:product_details/product_details.dart'; 18 | export 'package:settings/settings.dart'; 19 | -------------------------------------------------------------------------------- /features/home/lib/src/ui/components/sliver_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:home/src/home.dart'; 2 | 3 | class SliverGridList extends StatefulWidget { 4 | const SliverGridList({ 5 | super.key, 6 | required this.state, 7 | }); 8 | 9 | final LoadedProductsState state; 10 | 11 | @override 12 | State createState() => _SliverGridListState(); 13 | } 14 | 15 | class _SliverGridListState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return Stack( 19 | children: [ 20 | Positioned( 21 | child: Container( 22 | color: ApplicationColors.red, 23 | ), 24 | ) 25 | ], 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /data/lib/mapper/order.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | import 'package:data/model/order.dart'; 3 | 4 | class OrderMapper { 5 | static UserOrder toDomain(UserOrderEntity userOrderModel) { 6 | return UserOrder( 7 | id: userOrderModel.id, 8 | dateTime: userOrderModel.date, 9 | products: userOrderModel.products.map(ProductMapper.toEntity).toList(), 10 | price: userOrderModel.price, 11 | ); 12 | } 13 | 14 | static UserOrderEntity toModel(UserOrder userOrder) { 15 | return UserOrderEntity( 16 | id: userOrder.id, 17 | date: userOrder.dateTime, 18 | products: userOrder.products.map(ProductMapper.toModel).toList(), 19 | price: userOrder.price, 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /features/settings/lib/bloc/settings_state.dart: -------------------------------------------------------------------------------- 1 | part of 'settings_bloc.dart'; 2 | 3 | final class SettingsState extends Equatable { 4 | final FontSizeEntity fontSize; 5 | final Stream currentUser; 6 | 7 | const SettingsState({ 8 | required this.fontSize, 9 | required this.currentUser, 10 | }); 11 | 12 | @override 13 | List get props => [ 14 | fontSize, 15 | currentUser, 16 | ]; 17 | 18 | SettingsState copyWith({ 19 | FontSizeEntity? fontSize, 20 | Stream? currentUser, 21 | }) { 22 | return SettingsState( 23 | fontSize: fontSize ?? this.fontSize, 24 | currentUser: currentUser ?? this.currentUser, 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /features/home/lib/src/bloc/home/home_state.dart: -------------------------------------------------------------------------------- 1 | part of 'home_bloc.dart'; 2 | 3 | abstract class HomeState {} 4 | 5 | final class InitialProductsState extends HomeState {} 6 | 7 | final class LoadingProductsState extends HomeState {} 8 | 9 | final class LoadedProductsState extends HomeState { 10 | final List products; 11 | 12 | LoadedProductsState({ 13 | required this.products, 14 | }); 15 | } 16 | 17 | final class ErrorProductsState extends HomeState { 18 | final String error; 19 | 20 | ErrorProductsState({ 21 | required this.error, 22 | }); 23 | } 24 | 25 | final class NoInternetConnectionState extends HomeState { 26 | final String noInternetConnection = ConnectionConstants.connectionNotExists; 27 | } 28 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.7.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.3.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | tasks.register("clean", Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /core_ui/lib/components/gradient_backgaround.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | class GradientBackground extends StatelessWidget { 4 | final Widget child; 5 | final String image; 6 | 7 | const GradientBackground({ 8 | required this.child, 9 | required this.image, 10 | super.key, 11 | }); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Container( 16 | constraints: const BoxConstraints.expand(), 17 | decoration: BoxDecoration( 18 | image: DecorationImage( 19 | image: AssetImage( 20 | image, 21 | ), 22 | fit: BoxFit.cover, 23 | ), 24 | ), 25 | child: SafeArea(child: child), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /features/admin/lib/admin.dart: -------------------------------------------------------------------------------- 1 | library admin; 2 | 3 | export 'package:admin/bloc/admin/admin_bloc.dart'; 4 | export 'package:admin/bloc/users/bloc/users_bloc.dart'; 5 | export 'package:admin/ui/page/admin/page/admin_page.dart'; 6 | export 'package:admin/ui/page/dashboard/admin_dashboard_page.dart'; 7 | export 'package:admin/ui/page/product_count/product_counts_page.dart'; 8 | export 'package:admin/ui/page/sales/sales_page.dart'; 9 | export 'package:admin/ui/page/users/components/bar_chart.dart'; 10 | export 'package:admin/ui/page/users/components/card.dart'; 11 | export 'package:admin/ui/page/users/page/app_users_page.dart'; 12 | export 'package:core/core.dart'; 13 | export 'package:core_ui/core_ui.dart'; 14 | export 'package:navigation/navigation.dart'; 15 | -------------------------------------------------------------------------------- /data/lib/mapper/product.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | abstract class ProductMapper { 4 | static ProductModel toModel(Product model) { 5 | return ProductModel( 6 | model.name, 7 | model.description, 8 | model.image, 9 | model.price, 10 | model.ml, 11 | model.id, 12 | model.bigDescription, 13 | model.rate, 14 | ); 15 | } 16 | 17 | static Product toEntity(ProductModel model) { 18 | return Product( 19 | name: model.name, 20 | description: model.description, 21 | image: model.image, 22 | price: model.price, 23 | ml: model.ml, 24 | id: model.id, 25 | bigDescription: model.bigDescription, 26 | rate: model.rate, 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /data/lib/repository_impl/settings/font/font_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | import 'package:data/mapper/font_size.dart'; 3 | 4 | final class FontSizeRepositoryImpl extends FontSizeRepository { 5 | final LocaleDataSource _localeStorage; 6 | 7 | FontSizeRepositoryImpl({ 8 | required LocaleDataSource localeStorage, 9 | }) : _localeStorage = localeStorage; 10 | 11 | @override 12 | FontSizeEntity getFontSize() { 13 | final FontSizeModel model = _localeStorage.getFontSize(); 14 | return FontSizeMapper.toEntity(model); 15 | } 16 | 17 | @override 18 | Future saveFontSize(FontSizeEntity fontSize) async { 19 | await _localeStorage.saveFontSize( 20 | FontSizeMapper.toModel(fontSize), 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/lib/test.dart: -------------------------------------------------------------------------------- 1 | library test; 2 | 3 | export 'package:auth/auth.dart'; 4 | export 'package:bloc_test/bloc_test.dart'; 5 | export 'package:card/shopping_card.dart'; 6 | export 'package:core/core.dart'; 7 | export 'package:core_ui/core_ui.dart'; 8 | export 'package:data/data.dart'; 9 | export 'package:domain/domain.dart'; 10 | export 'package:fake_cloud_firestore/fake_cloud_firestore.dart'; 11 | export 'package:google_sign_in_mocks/google_sign_in_mocks.dart'; 12 | export 'package:home/src/home.dart'; 13 | export 'package:json_annotation/json_annotation.dart'; 14 | export 'package:mocktail/mocktail.dart'; 15 | export 'package:onboarding/onboarding.dart'; 16 | export 'package:settings/settings.dart'; 17 | export 'package:testing/widget/core_ui/test_wrapper_widget.dart'; 18 | -------------------------------------------------------------------------------- /features/product_details/lib/bloc/details/details_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:product_details/product_details.dart'; 2 | 3 | @immutable 4 | abstract class DetailsState {} 5 | 6 | final class InitialDetailsState extends DetailsState {} 7 | 8 | final class LoadingDetailsState extends DetailsState {} 9 | 10 | final class LoadedDetailsState extends DetailsState { 11 | final Product product; 12 | 13 | LoadedDetailsState({ 14 | required this.product, 15 | }); 16 | 17 | LoadedDetailsState copyWith({ 18 | required Product product, 19 | }) { 20 | return LoadedDetailsState( 21 | product: product, 22 | ); 23 | } 24 | } 25 | 26 | final class FailedDetailsState extends DetailsState { 27 | final String message; 28 | 29 | FailedDetailsState({ 30 | required this.message, 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /features/settings/lib/ui/components/list_tile.dart: -------------------------------------------------------------------------------- 1 | import 'package:settings/settings.dart'; 2 | 3 | class SettingsListTile extends StatelessWidget { 4 | final Widget _trailing; 5 | final Widget _leading; 6 | final VoidCallback _onTap; 7 | final String _title; 8 | 9 | const SettingsListTile({ 10 | super.key, 11 | required Widget trailing, 12 | required Widget leading, 13 | required VoidCallback onTap, 14 | required String title, 15 | }) : _trailing = trailing, 16 | _leading = leading, 17 | _onTap = onTap, 18 | _title = title; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return ListTile( 23 | onTap: _onTap, 24 | trailing: _trailing, 25 | title: Text( 26 | _title, 27 | ), 28 | leading: _leading, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /domain/lib/entity/product.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | @immutable 4 | final class Product extends Equatable { 5 | final String name; 6 | final String description; 7 | final String image; 8 | final int price; 9 | final int ml; 10 | final int id; 11 | final String bigDescription; 12 | final int rate; 13 | 14 | const Product({ 15 | required this.name, 16 | required this.description, 17 | required this.image, 18 | required this.price, 19 | required this.ml, 20 | required this.id, 21 | required this.bigDescription, 22 | required this.rate, 23 | }); 24 | 25 | @override 26 | List get props => [ 27 | name, 28 | description, 29 | image, 30 | price, 31 | ml, 32 | bigDescription, 33 | rate, 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /core_ui/lib/components/app_refresh_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | class AppRefreshView extends StatelessWidget { 4 | const AppRefreshView({ 5 | super.key, 6 | required this.size, 7 | required this.child, 8 | required this.onRefresh, 9 | }); 10 | 11 | final Widget child; 12 | final Size size; 13 | final Future Function() onRefresh; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return LiquidPullToRefresh( 18 | springAnimationDurationInMilliseconds: 1200, 19 | backgroundColor: ApplicationColors.black, 20 | animSpeedFactor: 20, 21 | key: const ValueKey(1), 22 | color: ApplicationColors.primaryButtonColor, 23 | height: size.height / Dimensions.SIZE_4, 24 | onRefresh: onRefresh, 25 | child: child, 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /data/lib/data_provider/locale/user/user_locale_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/exceptions/cache.dart'; 2 | import 'package:data/data.dart'; 3 | 4 | final class UserLocaleImpl extends UserLocale { 5 | late Box _userBox; 6 | 7 | @override 8 | Future saveUserFirstTime() async { 9 | try { 10 | await _userBox.put(LocaleStorage.userAuth.name, false); 11 | } catch (e) { 12 | throw CacheException(message: e.toString()); 13 | } 14 | } 15 | 16 | @override 17 | Future checkUserIfExists() async { 18 | try { 19 | return _userBox.get(LocaleStorage.userAuth.name) ?? true; 20 | } catch (e) { 21 | throw CacheException(message: e.toString()); 22 | } 23 | } 24 | 25 | @override 26 | Future initBox() async { 27 | _userBox = await Hive.openBox(LocaleStorage.userAuth.name); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /features/order/lib/bloc/order_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:order/order.dart'; 4 | 5 | part 'order_event.dart'; 6 | part 'order_state.dart'; 7 | 8 | class OrderBloc extends Bloc { 9 | final GetAllUserOrdersUseCase _getAllUserOrders; 10 | OrderBloc({ 11 | required GetAllUserOrdersUseCase getAllUserOrders, 12 | }) : _getAllUserOrders = getAllUserOrders, 13 | super(OrdersLoading()) { 14 | on(_onFetchAllOrders); 15 | } 16 | 17 | Future _onFetchAllOrders( 18 | FetchAllOrders event, 19 | Emitter emit, 20 | ) async { 21 | try { 22 | final List orders = _getAllUserOrders(); 23 | emit( 24 | OrdersLoaded(orders: orders), 25 | ); 26 | } catch (e) { 27 | emit(OrdersFailure()); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core_ui/lib/utils/utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | class Utils { 4 | static void showSnackBar(BuildContext context, String message) { 5 | ScaffoldMessenger.of(context) 6 | ..removeCurrentSnackBar() 7 | ..showSnackBar( 8 | SnackBar( 9 | content: Text( 10 | message, 11 | style: AppFonts.bold14, 12 | ), 13 | behavior: SnackBarBehavior.floating, 14 | backgroundColor: ApplicationColors.primaryButtonColor, 15 | shape: RoundedRectangleBorder( 16 | borderRadius: BorderRadius.circular( 17 | Dimensions.SIZE_10, 18 | ), 19 | ), 20 | margin: const EdgeInsets.symmetric( 21 | horizontal: Dimensions.SIZE_10, 22 | vertical: Dimensions.SIZE_10, 23 | ), 24 | ), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /navigation/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: navigation 2 | description: Application navigation layer 3 | version: 0.0.1 4 | publish_to: none 5 | environment: 6 | sdk: '>=3.0.5 <4.0.0' 7 | flutter: '>=1.17.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | auto_route: 5.0.4 13 | home: 14 | path: ../features/home/ 15 | card: 16 | path: ../features/card/ 17 | settings: 18 | path: ../features/settings/ 19 | order: 20 | path: ../features/order/ 21 | core: 22 | path: ../core/ 23 | dashboard: 24 | path: ../features/dashboard/ 25 | onboarding: 26 | path: ../features/onboarding/ 27 | auth: 28 | path: ../features/auth/ 29 | admin: 30 | path: ../features/admin/ 31 | 32 | dev_dependencies: 33 | flutter_test: 34 | sdk: flutter 35 | flutter_lints: ^2.0.0 36 | auto_route_generator: 5.0.2 37 | build_runner: ^2.3.3 38 | 39 | flutter: 40 | -------------------------------------------------------------------------------- /features/card/lib/bloc/cart_state.dart: -------------------------------------------------------------------------------- 1 | part of 'cart_bloc.dart'; 2 | 3 | @immutable 4 | abstract class CartState extends Equatable { 5 | const CartState(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | class CartLoading extends CartState { 12 | @override 13 | List get props => []; 14 | } 15 | 16 | class CartLoaded extends CartState { 17 | final Cart cart; 18 | final int serviceFee; 19 | 20 | const CartLoaded({ 21 | this.cart = const Cart(), 22 | this.serviceFee = 70, 23 | }); 24 | 25 | @override 26 | List get props => [ 27 | cart, 28 | ]; 29 | } 30 | 31 | class CartFailure extends CartState { 32 | final String message; 33 | const CartFailure({ 34 | required this.message, 35 | }); 36 | 37 | @override 38 | List get props => [ 39 | message, 40 | ]; 41 | } 42 | -------------------------------------------------------------------------------- /test/lib/widget/core_ui/app_button_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:testing/test.dart'; 3 | 4 | void main() { 5 | testWidgets( 6 | 'test app button', 7 | (WidgetTester widgetTester) async { 8 | await widgetTester.pumpWidget(TestWrapper( 9 | widget: PrimaryAppButton( 10 | icon: Icons.add, 11 | onPress: () {}, 12 | ), 13 | )); 14 | Finder button = find.byType(GestureDetector); 15 | expect(button, findsOneWidget); 16 | Finder icon = find.byIcon(AppIcons.increment); 17 | expect( 18 | icon, 19 | findsOneWidget, 20 | ); 21 | await widgetTester.tap( 22 | button, 23 | warnIfMissed: false, 24 | ); 25 | await widgetTester.pump(); 26 | expect( 27 | button, 28 | findsOneWidget, 29 | ); 30 | }, 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /data/lib/mapper/user.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/model/user.dart'; 2 | import 'package:domain/domain.dart'; 3 | 4 | abstract class UserMapper { 5 | static UserEntity toEntity(UserModel user) { 6 | return UserEntity( 7 | registrationDate: user.registrationDate, 8 | bio: user.bio, 9 | fullName: user.fullName, 10 | uid: user.uid, 11 | email: user.email, 12 | emailIsVerified: user.emailIsVerified, 13 | image: user.image, 14 | username: user.username, 15 | ); 16 | } 17 | 18 | static UserModel toModel(UserEntity user) { 19 | return UserModel( 20 | registrationDate: user.registrationDate, 21 | email: user.email, 22 | image: user.image, 23 | username: user.username, 24 | emailIsVerified: user.emailIsVerified, 25 | uid: user.uid, 26 | bio: user.bio, 27 | fullName: user.fullName); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/lib/widget/core_ui/app_text_field_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:testing/test.dart'; 3 | 4 | void main() { 5 | final TextEditingController textEditingController = TextEditingController(); 6 | const String testText = 'test'; 7 | testWidgets( 8 | 'test app text field', 9 | (WidgetTester tester) async { 10 | await tester.pumpWidget( 11 | TestWrapper( 12 | widget: AppTextField( 13 | controller: textEditingController, 14 | ), 15 | ), 16 | ); 17 | 18 | Finder finder = find.byType(TextField); 19 | expect( 20 | finder, 21 | findsOneWidget, 22 | ); 23 | await tester.enterText( 24 | find.byType(TextField), 25 | testText, 26 | ); 27 | expect( 28 | textEditingController.text, 29 | testText, 30 | ); 31 | }, 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /data/lib/model/order.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | part 'order.g.dart'; 4 | 5 | @HiveType(typeId: 3) 6 | @JsonSerializable() 7 | final class UserOrderEntity extends Equatable { 8 | @HiveField(0) 9 | final String id; 10 | 11 | @HiveField(1) 12 | final List products; 13 | 14 | @HiveField(2) 15 | final String date; 16 | 17 | @HiveField(3) 18 | final double price; 19 | 20 | const UserOrderEntity({ 21 | required this.id, 22 | required this.products, 23 | required this.date, 24 | required this.price, 25 | }); 26 | 27 | @override 28 | List get props => [ 29 | id, 30 | products, 31 | date, 32 | price, 33 | ]; 34 | 35 | factory UserOrderEntity.fromJson(Map json) => 36 | _$UserOrderEntityFromJson(json); 37 | 38 | Map toJson() => _$UserOrderEntityToJson(this); 39 | } 40 | -------------------------------------------------------------------------------- /domain/lib/usecase/auth/sign_in_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | class SignInUseCase extends FutureUseCaseWithParams { 4 | final AuthRepository _repository; 5 | 6 | const SignInUseCase( 7 | AuthRepository repository, 8 | ) : _repository = repository; 9 | 10 | @override 11 | ResultFuture call(SignInParams params) => _repository.signIn( 12 | email: params.email, 13 | password: params.password, 14 | ); 15 | } 16 | 17 | class SignInParams extends Equatable { 18 | final String email; 19 | final String password; 20 | 21 | const SignInParams({ 22 | required this.email, 23 | required this.password, 24 | }); 25 | 26 | const SignInParams.empty() 27 | : email = '', 28 | password = ''; 29 | 30 | @override 31 | List get props => [ 32 | email, 33 | password, 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /core_ui/lib/components/app_rating_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | class AppRatingBar extends StatelessWidget { 4 | const AppRatingBar({ 5 | required this.rate, 6 | super.key, 7 | }); 8 | 9 | final double rate; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return RatingBar.builder( 14 | glow: false, 15 | itemSize: Dimensions.SIZE_20, 16 | ignoreGestures: true, 17 | tapOnlyMode: false, 18 | onRatingUpdate: (double value) {}, 19 | initialRating: rate, 20 | maxRating: Dimensions.SIZE_5, 21 | itemCount: Dimensions.SIZE_5.toInt(), 22 | itemPadding: const EdgeInsets.symmetric( 23 | horizontal: ApplicationPadding.PADDING_4, 24 | ), 25 | itemBuilder: (BuildContext context, _) => const Icon( 26 | Icons.star, 27 | color: ApplicationColors.primaryButtonColor, 28 | ), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/lib/exceptions/failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/core.dart'; 2 | import 'package:core/exceptions/server.dart'; 3 | 4 | abstract class Failure extends Equatable { 5 | const Failure({ 6 | required this.message, 7 | required this.statusCode, 8 | }); 9 | 10 | final String message; 11 | final dynamic statusCode; 12 | 13 | String get errorMessage => '$statusCode Error: $message'; 14 | 15 | @override 16 | List get props => [ 17 | message, 18 | statusCode, 19 | ]; 20 | } 21 | 22 | class CacheFailure extends Failure { 23 | const CacheFailure({ 24 | required super.message, 25 | required super.statusCode, 26 | }); 27 | } 28 | 29 | class ServerFailure extends Failure { 30 | const ServerFailure({required super.message, required super.statusCode}); 31 | 32 | ServerFailure.fromException(ServerException exception) 33 | : this(message: exception.message, statusCode: exception.statusCode); 34 | } 35 | -------------------------------------------------------------------------------- /core_ui/lib/components/rounded_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | class RoundedButton extends StatelessWidget { 4 | final String label; 5 | final VoidCallback onPressed; 6 | final Color? buttonColor; 7 | final Color? labelColor; 8 | 9 | const RoundedButton({ 10 | required this.label, 11 | required this.onPressed, 12 | this.buttonColor, 13 | this.labelColor, 14 | super.key, 15 | }); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return ElevatedButton( 20 | style: ElevatedButton.styleFrom( 21 | backgroundColor: buttonColor ?? ApplicationColors.primaryButtonColor, 22 | foregroundColor: labelColor ?? ApplicationColors.white, 23 | minimumSize: const Size( 24 | double.maxFinite, 25 | Dimensions.SIZE_50, 26 | ), 27 | ), 28 | onPressed: onPressed, 29 | child: Text( 30 | label, 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /data/lib/model/product.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | part 'product.g.dart'; 4 | 5 | @JsonSerializable() 6 | @HiveType(typeId: 1) 7 | class ProductModel { 8 | @HiveField(0) 9 | final String name; 10 | @HiveField(1) 11 | final String description; 12 | @HiveField(2) 13 | final String image; 14 | @HiveField(3) 15 | final int price; 16 | @HiveField(4) 17 | final int ml; 18 | @HiveField(5) 19 | final int id; 20 | @HiveField(6) 21 | final String bigDescription; 22 | @HiveField(7) 23 | final int rate; 24 | 25 | ProductModel( 26 | this.name, 27 | this.description, 28 | this.image, 29 | this.price, 30 | this.ml, 31 | this.id, 32 | this.bigDescription, 33 | this.rate, 34 | ); 35 | 36 | factory ProductModel.fromJson(Map json) { 37 | return _$ProductModelFromJson(json); 38 | } 39 | 40 | Map toJson() { 41 | return _$ProductModelToJson(this); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /features/admin/lib/bloc/users/bloc/users_state.dart: -------------------------------------------------------------------------------- 1 | part of 'users_bloc.dart'; 2 | 3 | @immutable 4 | sealed class UsersState {} 5 | 6 | final class UsersInitial extends UsersState {} 7 | 8 | final class UsersLoading extends UsersState {} 9 | 10 | class UsersLoaded extends UsersState { 11 | final List usersByDate; 12 | final List users; 13 | final List ordersByDate; 14 | UsersLoaded({ 15 | required this.ordersByDate, 16 | required this.usersByDate, 17 | required this.users, 18 | }); 19 | 20 | UsersLoaded copyWith({ 21 | bool? isShowDailyUserStatics, 22 | List? usersByDate, 23 | List? users, 24 | List? ordersByDate, 25 | }) { 26 | return UsersLoaded( 27 | ordersByDate: ordersByDate ?? this.ordersByDate, 28 | usersByDate: usersByDate ?? this.usersByDate, 29 | users: users ?? this.users, 30 | ); 31 | } 32 | } 33 | 34 | final class UsersFailed extends UsersState {} 35 | -------------------------------------------------------------------------------- /.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 | .features/order/pubspec.loc/ 24 | .features/order/analysis_options.yaml/ 25 | .settings.json 26 | 27 | # Flutter/Dart/Pub related 28 | **/doc/api/ 29 | **/ios/Flutter/.last_build_id 30 | .dart_tool/ 31 | .flutter-plugins 32 | .flutter-plugins-dependencies 33 | .packages 34 | .pub-cache/ 35 | .pub/ 36 | /build/ 37 | 38 | # Symbolication related 39 | app.*.symbols 40 | 41 | # Obfuscation related 42 | app.*.map.json 43 | 44 | # Android Studio will place build artifacts here 45 | /android/app/debug 46 | /android/app/profile 47 | /android/app/release 48 | -------------------------------------------------------------------------------- /data/lib/repository_impl/cart/cart_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | final class CartRepositoryImpl extends CartRepository { 4 | final LocaleDataSource _localeStorage; 5 | 6 | CartRepositoryImpl({ 7 | required LocaleDataSource localeStorage, 8 | }) : _localeStorage = localeStorage; 9 | 10 | @override 11 | Future addCartItem(Product product) async { 12 | await _localeStorage.addCartItem(ProductMapper.toModel(product)); 13 | } 14 | 15 | @override 16 | List getCartAllCartItems() { 17 | final List cartItems = _localeStorage.getAllCartItems(); 18 | return cartItems.map(ProductMapper.toEntity).toList(); 19 | } 20 | 21 | @override 22 | Future removeAllCartItems() async { 23 | await _localeStorage.removeAllCartItems(); 24 | } 25 | 26 | @override 27 | Future removeCartItem(Product product) async { 28 | await _localeStorage.removeCartItem(ProductMapper.toModel(product)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /data/lib/data_provider/locale/locale_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | import 'package:data/model/order.dart'; 3 | 4 | abstract class LocaleDataSource { 5 | //init 6 | Future initBox(); 7 | //!Order 8 | Future addOrder(UserOrderEntity orderModel); 9 | 10 | List getAllOrders(); 11 | 12 | //!Theme 13 | Future saveAppTheme(bool isDark); 14 | 15 | Future getAppTheme(String key); 16 | 17 | //!Cart 18 | Future addCartItem(ProductModel model); 19 | 20 | Future removeCartItem(ProductModel model); 21 | 22 | List getAllCartItems(); 23 | 24 | Future removeAllCartItems(); 25 | 26 | //!Products 27 | 28 | Future addProducts(List products); 29 | 30 | List getAllProducts(); 31 | 32 | Future getProductById(int productId); 33 | 34 | //!FontSize 35 | Future saveFontSize(FontSizeModel model); 36 | 37 | FontSizeModel getFontSize(); 38 | } 39 | -------------------------------------------------------------------------------- /features/card/lib/bloc/cart_event.dart: -------------------------------------------------------------------------------- 1 | part of 'cart_bloc.dart'; 2 | 3 | @immutable 4 | abstract class CartEvent extends Equatable { 5 | const CartEvent(); 6 | 7 | @override 8 | List get props => []; 9 | } 10 | 11 | class LoadCart extends CartEvent {} 12 | 13 | class AddProduct extends CartEvent { 14 | final Product product; 15 | 16 | const AddProduct(this.product); 17 | 18 | @override 19 | List get props => [ 20 | product, 21 | ]; 22 | } 23 | 24 | class RemoveProduct extends CartEvent { 25 | final Product product; 26 | 27 | const RemoveProduct(this.product); 28 | 29 | @override 30 | List get props => [ 31 | product, 32 | ]; 33 | } 34 | 35 | final class RemoveAllProducts extends CartEvent { 36 | const RemoveAllProducts(); 37 | 38 | @override 39 | List get props => []; 40 | } 41 | 42 | final class ConfirmOrder extends CartEvent { 43 | @override 44 | List get props => []; 45 | } 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /core/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: core 2 | description: Core Module. 3 | version: 0.0.1 4 | publish_to: none 5 | environment: 6 | sdk: '>=3.0.0 <4.0.0' 7 | flutter: '>=1.17.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | #firebase 14 | cloud_firestore: ^4.8.1 15 | firebase_core: ^2.14.0 16 | firebase_auth: ^4.7.2 17 | google_sign_in: ^5.0.2 18 | firebase_storage: ^11.2.0 19 | #dependency injection 20 | get_it: ^7.6.0 21 | #base 22 | equatable: ^2.0.5 23 | #bloc 24 | flutter_bloc: ^8.1.3 25 | bloc: ^8.1.2 26 | #locale storage 27 | hive_flutter: ^1.1.0 28 | hive: ^2.2.3 29 | #connection 30 | internet_connection_checker: ^1.0.0+1 31 | #url uncher 32 | url_launcher: ^6.1.12 33 | #dartz 34 | dartz: ^0.10.1 35 | #provider 36 | provider: ^6.0.5 37 | #image picker 38 | image_picker: ^1.0.1 39 | #uuid 40 | uuid: ^3.0.7 41 | #intl 42 | intl: any 43 | 44 | dev_dependencies: 45 | flutter_test: 46 | sdk: flutter 47 | flutter_lints: ^2.0.0 48 | 49 | flutter: 50 | -------------------------------------------------------------------------------- /core_ui/lib/constants/image_path.dart: -------------------------------------------------------------------------------- 1 | final class ImagePaths { 2 | static const String sliverAppBarBackground = 3 | 'assets/images/sliver_appbar.jpg'; 4 | 5 | static const String nightIcon = 'assets/images/night_icon.png'; 6 | static const String dayIcon = 'assets/images/day_icon.png'; 7 | static const String emptyCart = 'assets/lottie/empty.json'; 8 | static const String person = 'assets/images/person.jpg'; 9 | static const String onBoardingFirst = 'assets/images/onboarding_1.png'; 10 | static const String onBoardingSecond = 'assets/images/onboarding_2.png'; 11 | static const String onBoardingThird = 'assets/images/onboarding_3.png'; 12 | static const String authGradientBackground = 13 | 'assets/images/auth_gradient_background.png'; 14 | static const String onBoardingBackground = 15 | 'assets/images/onBoarding_background.png'; 16 | 17 | static const String profileGradientBackground = 18 | 'assets/images/onBoarding_background.png'; 19 | static const String user = 'assets/images/user.png'; 20 | } 21 | -------------------------------------------------------------------------------- /test/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: testing 2 | description: Application test layer. 3 | version: 0.0.1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: '>=3.0.0 <4.0.0' 8 | flutter: '>=1.17.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | bloc_test: ^9.1.4 14 | core: 15 | path: ../core 16 | core_ui: 17 | path: ../core_ui 18 | domain: 19 | path: ../domain 20 | data: 21 | path: ../data 22 | home: 23 | path: ../features/home/ 24 | card: 25 | path: ../features/card/ 26 | settings: 27 | path: ../features/settings/ 28 | order: 29 | path: ../features/order/ 30 | dashboard: 31 | path: ../features/dashboard/ 32 | onboarding: 33 | path: ../features/onboarding/ 34 | auth: 35 | path: ../features/auth/ 36 | 37 | dev_dependencies: 38 | flutter_test: 39 | sdk: flutter 40 | 41 | flutter_lints: ^2.0.0 42 | mocktail: ^1.0.0 43 | fake_cloud_firestore: ^2.4.1+1 44 | firebase_auth_mocks: ^0.12.0 45 | firebase_storage_mocks: ^0.6.1 46 | google_sign_in_mocks: ^0.2.2 47 | -------------------------------------------------------------------------------- /features/home/lib/src/ui/components/home_shadow.dart: -------------------------------------------------------------------------------- 1 | import 'package:home/src/home.dart'; 2 | 3 | class HomeProductShadow extends StatelessWidget { 4 | const HomeProductShadow({ 5 | required this.size, 6 | super.key, 7 | }); 8 | 9 | final Size size; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Positioned( 14 | left: Dimensions.SIZE_20, 15 | right: Dimensions.SIZE_20, 16 | bottom: -size.height * Dimensions.SIZE_0_2, 17 | height: size.height * Dimensions.SIZE_0_4, 18 | child: DecoratedBox( 19 | decoration: BoxDecoration( 20 | shape: BoxShape.circle, 21 | boxShadow: [ 22 | BoxShadow( 23 | color: ApplicationColors.disabledColor 24 | .withOpacity(Dimensions.SIZE_0_2), 25 | blurRadius: Dimensions.SIZE_40, 26 | offset: Offset.zero, 27 | spreadRadius: Dimensions.SIZE_50, 28 | ) 29 | ], 30 | ), 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /features/product_details/lib/bloc/details/details_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:product_details/product_details.dart'; 2 | 3 | class DetailsBloc extends Bloc { 4 | final FetchProductByIdUseCase _fetchProductByIdUseCase; 5 | 6 | DetailsBloc( 7 | FetchProductByIdUseCase fetchProductByIdUseCase, 8 | ) : _fetchProductByIdUseCase = fetchProductByIdUseCase, 9 | super( 10 | InitialDetailsState(), 11 | ) { 12 | on(_fetchProductByIdEvent); 13 | } 14 | Future _fetchProductByIdEvent( 15 | FetchProductEvent event, Emitter emit) async { 16 | emit(LoadingDetailsState()); 17 | try { 18 | final Product data = await _fetchProductByIdUseCase.call( 19 | event.productId, 20 | ); 21 | emit( 22 | LoadedDetailsState( 23 | product: data, 24 | ), 25 | ); 26 | } catch (e) { 27 | emit( 28 | FailedDetailsState( 29 | message: e.toString(), 30 | ), 31 | ); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core_ui/lib/components/app_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | class CartButton extends StatelessWidget { 4 | final VoidCallback onPressed; 5 | final String text; 6 | final double textScaleFactory = 1; 7 | const CartButton({ 8 | required this.onPressed, 9 | required this.text, 10 | super.key, 11 | }); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return ElevatedButton( 16 | onPressed: onPressed, 17 | style: ElevatedButton.styleFrom( 18 | backgroundColor: ApplicationColors.primaryButtonColor, 19 | shape: RoundedRectangleBorder( 20 | borderRadius: BorderRadius.circular( 21 | ApplicationPadding.PADDING_20, 22 | ), 23 | ), 24 | elevation: Dimensions.SIZE_8, 25 | shadowColor: ApplicationColors.black, 26 | ), 27 | child: Text( 28 | text, 29 | style: AppFonts.normal18.copyWith( 30 | color: ApplicationColors.black, 31 | ), 32 | textScaleFactor: textScaleFactory, 33 | ), 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /domain/lib/usecase/auth/sign_up_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | class SignUpUseCase extends FutureUseCaseWithParams { 4 | final AuthRepository _repository; 5 | 6 | const SignUpUseCase( 7 | AuthRepository repository, 8 | ) : _repository = repository; 9 | 10 | @override 11 | ResultFuture call(SignUpParams params) => _repository.signUp( 12 | email: params.email, 13 | password: params.password, 14 | fullName: params.fullName, 15 | ); 16 | } 17 | 18 | class SignUpParams extends Equatable { 19 | final String email; 20 | final String password; 21 | final String fullName; 22 | 23 | const SignUpParams({ 24 | required this.email, 25 | required this.password, 26 | required this.fullName, 27 | }); 28 | 29 | const SignUpParams.empty() 30 | : this( 31 | email: '', 32 | password: '', 33 | fullName: '', 34 | ); 35 | 36 | @override 37 | List get props => [ 38 | email, 39 | password, 40 | fullName, 41 | ]; 42 | } 43 | -------------------------------------------------------------------------------- /core_ui/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: core_ui 2 | description: A new Flutter package project. 3 | version: 0.0.1 4 | publish_to: none 5 | environment: 6 | sdk: '>=3.0.0 <4.0.0' 7 | flutter: '>=1.17.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | core: 14 | path: ../core/ 15 | 16 | #Fonts 17 | google_fonts: ^4.0.4 18 | #cahce image 19 | cached_network_image: ^3.2.3 20 | #loading widget 21 | flutter_spinkit: ^5.2.0 22 | #animated text 23 | animated_text_kit: ^4.2.2 24 | #rating bar 25 | flutter_rating_bar: ^4.0.1 26 | #svg 27 | flutter_svg: ^2.0.7 28 | #lottie 29 | lottie: ^2.4.0 30 | #slidable 31 | flutter_slidable: ^3.0.0 32 | #snackBar 33 | awesome_snackbar_content: ^0.1.3 34 | #refresh screen 35 | liquid_pull_to_refresh: ^3.0.1 36 | #toast 37 | fluttertoast: ^8.2.2 38 | #Smooth page indicator: 39 | smooth_page_indicator: ^1.1.0 40 | #corusel slider 41 | carousel_slider: ^4.2.1 42 | #chart 43 | fl_chart: ^0.63.0 44 | 45 | dev_dependencies: 46 | flutter_test: 47 | sdk: flutter 48 | flutter_lints: ^2.0.0 49 | 50 | flutter: 51 | -------------------------------------------------------------------------------- /data/lib/repository_impl/order/order_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | class OrderRepositoryImpl extends OrderRepository { 4 | final LocaleDataSource _localeDataSource; 5 | final RemoteOrderDataSource _remoteOrderDataSource; 6 | 7 | OrderRepositoryImpl( 8 | this._localeDataSource, 9 | this._remoteOrderDataSource, 10 | ); 11 | 12 | @override 13 | List getAllOrders() { 14 | return _localeDataSource 15 | .getAllOrders() 16 | .map(OrderMapper.toDomain) 17 | .toList(); 18 | } 19 | 20 | @override 21 | Future saveOrderLocale(UserOrder userOrder) async { 22 | return _localeDataSource.addOrder( 23 | OrderMapper.toModel(userOrder), 24 | ); 25 | } 26 | 27 | @override 28 | Future saveOrderToFirebase(UserOrder userOrder) { 29 | return _remoteOrderDataSource.saveOrderToFirebase( 30 | OrderMapper.toModel(userOrder), 31 | ); 32 | } 33 | 34 | @override 35 | Future> getOrdersPerDay() async { 36 | return await _remoteOrderDataSource.getOrdersPerDay(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /features/home/lib/src/ui/components/home_title.dart: -------------------------------------------------------------------------------- 1 | import 'package:home/src/home.dart'; 2 | 3 | class HomeTitle extends StatelessWidget { 4 | final double _currentPage; 5 | final LoadedProductsState _state; 6 | const HomeTitle({ 7 | required double currentPage, 8 | required LoadedProductsState state, 9 | super.key, 10 | }) : _currentPage = currentPage, 11 | _state = state; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Positioned( 16 | right: Dimensions.SIZE_0, 17 | left: Dimensions.SIZE_0, 18 | top: Dimensions.SIZE_40, 19 | height: Dimensions.SIZE_75, 20 | child: Column( 21 | children: [ 22 | Text( 23 | _state.products[_currentPage.toInt()].name, 24 | style: AppFonts.bold24, 25 | overflow: TextOverflow.ellipsis, 26 | ), 27 | Text( 28 | '${_state.products[_currentPage.toInt()].price.toString()} ${Currency.rubl.value}', 29 | style: AppFonts.bold18, 30 | ), 31 | ], 32 | ), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core_ui/lib/components/app_add_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | class PrimaryAppButton extends StatelessWidget { 4 | final IconData _icon; 5 | final VoidCallback _onPress; 6 | const PrimaryAppButton({ 7 | required IconData icon, 8 | required VoidCallback onPress, 9 | super.key, 10 | }) : _icon = icon, 11 | _onPress = onPress; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Padding( 16 | padding: const EdgeInsets.all( 17 | ApplicationPadding.PADDING_12, 18 | ), 19 | child: GestureDetector( 20 | onTap: _onPress, 21 | child: DecoratedBox( 22 | decoration: const BoxDecoration( 23 | borderRadius: BorderRadius.all( 24 | Radius.circular( 25 | Dimensions.SIZE_20, 26 | ), 27 | ), 28 | color: ApplicationColors.primaryButtonColor, 29 | ), 30 | child: Icon( 31 | _icon, 32 | size: Dimensions.SIZE_20, 33 | ), 34 | ), 35 | ), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ali Altiyev 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 | -------------------------------------------------------------------------------- /features/settings/lib/cubit/theme_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:settings/settings.dart'; 2 | 3 | part 'theme_state.dart'; 4 | 5 | class ThemeCubit extends Cubit { 6 | final SaveAppThemeUseCase _saveAppThemeUseCase; 7 | final GetAppThemeUseCase _getAppThemeUseCase; 8 | bool _isDark = false; 9 | bool _iconState = false; 10 | bool get isDark => _isDark; 11 | bool get iconState => _iconState; 12 | 13 | ThemeCubit({ 14 | required SaveAppThemeUseCase saveAppThemeUseCase, 15 | required GetAppThemeUseCase getAppThemeUseCase, 16 | }) : _saveAppThemeUseCase = saveAppThemeUseCase, 17 | _getAppThemeUseCase = getAppThemeUseCase, 18 | super(ThemeInitial()) { 19 | _isDark = false; 20 | getTheme(); 21 | } 22 | 23 | set isDark(bool value) { 24 | _isDark = value; 25 | _saveAppThemeUseCase.call(value); 26 | emit(ThemeChanged()); 27 | } 28 | 29 | Future getTheme() async { 30 | _isDark = await _getAppThemeUseCase.call(LocaleStorage.key.name); 31 | emit(ThemeChanged()); 32 | } 33 | 34 | void changeIcon() { 35 | isDark = !isDark; 36 | _iconState = !_iconState; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /features/settings/lib/bloc/settings_event.dart: -------------------------------------------------------------------------------- 1 | part of 'settings_bloc.dart'; 2 | 3 | abstract class SettingsEvent extends Equatable {} 4 | 5 | final class SaveFontSizeEvent extends SettingsEvent { 6 | final FontSizeEntity fontSizeEntity; 7 | 8 | SaveFontSizeEvent({ 9 | required this.fontSizeEntity, 10 | }); 11 | 12 | @override 13 | List get props => [ 14 | fontSizeEntity, 15 | ]; 16 | } 17 | 18 | final class GetFontSizeEvent extends SettingsEvent { 19 | @override 20 | List get props => []; 21 | } 22 | 23 | final class LaunchContactsEvent extends SettingsEvent { 24 | @override 25 | List get props => []; 26 | } 27 | 28 | final class SignOutFromAppEvent extends SettingsEvent { 29 | @override 30 | List get props => []; 31 | } 32 | 33 | final class PopEvent extends SettingsEvent { 34 | @override 35 | List get props => []; 36 | } 37 | 38 | final class ChangeAvatarImage extends SettingsEvent { 39 | @override 40 | List get props => []; 41 | } 42 | 43 | final class NavigateToEditProfileEvent extends SettingsEvent { 44 | @override 45 | List get props => []; 46 | } 47 | -------------------------------------------------------------------------------- /data/lib/model/user.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'user.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | UserModel _$UserModelFromJson(Map json) => UserModel( 10 | registrationDate: json['registrationDate'] as Timestamp, 11 | fullName: json['fullName'] as String, 12 | bio: json['bio'] as String?, 13 | uid: json['uid'] as String, 14 | emailIsVerified: json['emailIsVerified'] as bool?, 15 | image: json['image'] as String?, 16 | email: json['email'] as String, 17 | username: json['username'] as String, 18 | ); 19 | 20 | Map _$UserModelToJson(UserModel instance) => { 21 | 'email': instance.email, 22 | 'uid': instance.uid, 23 | 'bio': instance.bio, 24 | 'fullName': instance.fullName, 25 | 'emailIsVerified': instance.emailIsVerified, 26 | 'image': instance.image, 27 | 'username': instance.username, 28 | 'registrationDate': instance.registrationDate, 29 | }; 30 | -------------------------------------------------------------------------------- /features/auth/lib/bloc/auth_state.dart: -------------------------------------------------------------------------------- 1 | part of 'auth_bloc.dart'; 2 | 3 | abstract class AuthState extends Equatable { 4 | const AuthState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class AuthInitialState extends AuthState { 11 | const AuthInitialState(); 12 | } 13 | 14 | class AuthLoadingState extends AuthState { 15 | const AuthLoadingState(); 16 | 17 | @override 18 | List get props => []; 19 | } 20 | 21 | class AuthError extends AuthState { 22 | const AuthError({required this.message}); 23 | 24 | final String message; 25 | 26 | @override 27 | List get props => [ 28 | message, 29 | ]; 30 | } 31 | 32 | class SignedInState extends AuthState { 33 | const SignedInState({required this.user}); 34 | 35 | final UserEntity user; 36 | 37 | @override 38 | List get props => [ 39 | user, 40 | ]; 41 | } 42 | 43 | class SignedUpState extends AuthState { 44 | const SignedUpState(); 45 | } 46 | 47 | class ForgotPasswordSent extends AuthState { 48 | const ForgotPasswordSent(); 49 | } 50 | 51 | class UserUpdated extends AuthState { 52 | const UserUpdated(); 53 | } 54 | -------------------------------------------------------------------------------- /domain/lib/entity/user.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | @immutable 4 | final class UserEntity extends Equatable { 5 | final String email; 6 | final String uid; 7 | final String? bio; 8 | final String fullName; 9 | final bool? emailIsVerified; 10 | final String? image; 11 | final String username; 12 | final Timestamp registrationDate; 13 | 14 | const UserEntity( 15 | {required this.fullName, 16 | required this.bio, 17 | required this.uid, 18 | required this.emailIsVerified, 19 | required this.image, 20 | required this.email, 21 | required this.username, 22 | required this.registrationDate}); 23 | 24 | UserEntity.empty() 25 | : this( 26 | registrationDate: Timestamp.now(), 27 | emailIsVerified: true, 28 | image: '', 29 | username: '', 30 | uid: '', 31 | email: '', 32 | fullName: '', 33 | bio: '', 34 | ); 35 | 36 | @override 37 | List get props => [ 38 | username, 39 | image, 40 | email, 41 | emailIsVerified, 42 | uid, 43 | fullName, 44 | bio, 45 | ]; 46 | } 47 | -------------------------------------------------------------------------------- /data/lib/repository_impl/onboarding/on_boarding_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:core/exceptions/cache.dart'; 2 | import 'package:data/data.dart'; 3 | 4 | export 'package:data/data.dart'; 5 | 6 | class OnBoardingRepositoryImpl implements OnBoardingRepository { 7 | final UserLocale _userLocale; 8 | 9 | const OnBoardingRepositoryImpl( 10 | this._userLocale, 11 | ); 12 | 13 | @override 14 | ResultFuture cacheFirstTimer() async { 15 | try { 16 | await _userLocale.saveUserFirstTime(); 17 | return const Right(null); 18 | } on CacheException catch (e) { 19 | return Left( 20 | CacheFailure( 21 | message: e.message, 22 | statusCode: e.statusCode, 23 | ), 24 | ); 25 | } 26 | } 27 | 28 | @override 29 | ResultFuture checkIfUserIsFirstTimer() async { 30 | try { 31 | final bool result = await _userLocale.checkUserIfExists(); 32 | return Right(result); 33 | } on CacheException catch (e) { 34 | return Left( 35 | CacheFailure( 36 | message: e.message, 37 | statusCode: e.statusCode, 38 | ), 39 | ); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/lib/unit/domain/usecase/auth/log_out_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:testing/test.dart'; 3 | 4 | class MockAuthRepository extends Mock implements AuthRepository {} 5 | 6 | void main() { 7 | late LogOutUseCase logOutUseCase; 8 | late AuthRepository authRepository; 9 | 10 | setUp( 11 | () { 12 | authRepository = MockAuthRepository(); 13 | logOutUseCase = LogOutUseCase(authRepository); 14 | }, 15 | ); 16 | LogOutUseCaseParams params = LogOutUseCaseParams(); 17 | 18 | test( 19 | 'should call the [AuthRepository.logOut()]', 20 | () async { 21 | //arrange 22 | when>>( 23 | () => authRepository.logOut(), 24 | ).thenAnswer((_) async => const Right(null)); 25 | 26 | //act 27 | final Either result = await logOutUseCase(params); 28 | 29 | // assert 30 | expect( 31 | result, 32 | equals( 33 | const Right(null), 34 | ), 35 | ); 36 | 37 | verify( 38 | () => authRepository.logOut(), 39 | ).called(1); 40 | 41 | verifyNoMoreInteractions(authRepository); 42 | }, 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /data/lib/model/font_size.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'font_size.dart'; 4 | 5 | // ************************************************************************** 6 | // TypeAdapterGenerator 7 | // ************************************************************************** 8 | 9 | class FontSizeModelAdapter extends TypeAdapter { 10 | @override 11 | final int typeId = 2; 12 | 13 | @override 14 | FontSizeModel read(BinaryReader reader) { 15 | final numOfFields = reader.readByte(); 16 | final fields = { 17 | for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), 18 | }; 19 | return FontSizeModel( 20 | fontSize: fields[0] as double, 21 | ); 22 | } 23 | 24 | @override 25 | void write(BinaryWriter writer, FontSizeModel obj) { 26 | writer 27 | ..writeByte(1) 28 | ..writeByte(0) 29 | ..write(obj.fontSize); 30 | } 31 | 32 | @override 33 | int get hashCode => typeId.hashCode; 34 | 35 | @override 36 | bool operator ==(Object other) => 37 | identical(this, other) || 38 | other is FontSizeModelAdapter && 39 | runtimeType == other.runtimeType && 40 | typeId == other.typeId; 41 | } 42 | -------------------------------------------------------------------------------- /domain/lib/entity/page_content.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | class PageContent extends Equatable { 4 | final String image; 5 | final String title; 6 | final String description; 7 | 8 | const PageContent({ 9 | required this.image, 10 | required this.title, 11 | required this.description, 12 | }); 13 | 14 | const PageContent.first() 15 | : this( 16 | image: ImagePaths.onBoardingFirst, 17 | title: 'Еда, полезная для вас и планеты', 18 | description: 'Amazox Prime: Еда, которая объединяет людей.', 19 | ); 20 | 21 | const PageContent.second() 22 | : this( 23 | image: ImagePaths.onBoardingSecond, 24 | title: 'Еда, которая делает вас счастливым', 25 | description: 'Еда, которую вы любите, доставлена ​​к вашей двери', 26 | ); 27 | 28 | const PageContent.third() 29 | : this( 30 | image: ImagePaths.onBoardingThird, 31 | title: ''' 32 | Доставка еды: быстрая, свежая и доступная''', 33 | description: ''' 34 | Еда, которая стоит ожидания''', 35 | ); 36 | 37 | @override 38 | List get props => [ 39 | image, 40 | title, 41 | description, 42 | ]; 43 | } 44 | -------------------------------------------------------------------------------- /features/card/lib/ui/page/shopping_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:card/shopping_card.dart'; 2 | 3 | class ShappingCard extends StatefulWidget { 4 | const ShappingCard({super.key}); 5 | 6 | @override 7 | State createState() => _SettingsPageState(); 8 | } 9 | 10 | class _SettingsPageState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | body: BlocBuilder( 15 | builder: (BuildContext context, CartState state) { 16 | if (state is CartLoaded) { 17 | if (state.cart.cartItems.isNotEmpty) { 18 | return CartBody( 19 | state: state, 20 | ); 21 | } else { 22 | return const EmptyCartBody(); 23 | } 24 | } else if (state is CartLoading) { 25 | return const Center( 26 | child: CircularProgressIndicator.adaptive( 27 | backgroundColor: ApplicationColors.primaryButtonColor, 28 | ), 29 | ); 30 | } else { 31 | return const Center( 32 | child: SizedBox.shrink(), 33 | ); 34 | } 35 | }, 36 | ), 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ios/Runner/GoogleService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CLIENT_ID 6 | 733275854742-ug8aq40d52v3s4dih2s799m7qng57spg.apps.googleusercontent.com 7 | REVERSED_CLIENT_ID 8 | com.googleusercontent.apps.733275854742-ug8aq40d52v3s4dih2s799m7qng57spg 9 | API_KEY 10 | AIzaSyD3_x76M61G0xolSo8NGdnbuo8QL78-GIs 11 | GCM_SENDER_ID 12 | 733275854742 13 | PLIST_VERSION 14 | 1 15 | BUNDLE_ID 16 | com.example.amazonPrime 17 | PROJECT_ID 18 | innofire-ccce6 19 | STORAGE_BUCKET 20 | innofire-ccce6.appspot.com 21 | IS_ADS_ENABLED 22 | 23 | IS_ANALYTICS_ENABLED 24 | 25 | IS_APPINVITE_ENABLED 26 | 27 | IS_GCM_ENABLED 28 | 29 | IS_SIGNIN_ENABLED 30 | 31 | GOOGLE_APP_ID 32 | 1:733275854742:ios:343a72426a5d2f9c652fb7 33 | 34 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: amazon_prime 2 | description: Flutter 3 | 4 | publish_to: none 5 | 6 | version: 1.0.0+1 7 | 8 | environment: 9 | sdk: '>=3.0.0 <4.0.0' 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | cupertino_icons: ^1.0.2 15 | 16 | core: 17 | path: ./core/ 18 | data: 19 | path: ./data/ 20 | core_ui: 21 | path: ./core_ui/ 22 | navigation: 23 | path: ./navigation/ 24 | home: 25 | path: ./features/home/ 26 | admin: 27 | path: ./features/admin/ 28 | 29 | settings: 30 | path: ./features/settings/ 31 | card: 32 | path: ./features/card/ 33 | order: 34 | path: ./features/order 35 | 36 | dev_dependencies: 37 | flutter_test: 38 | sdk: flutter 39 | flutter_lints: ^2.0.0 40 | flutter_launcher_icons: '^0.13.1' 41 | 42 | flutter_icons: 43 | android: 'launcher_icon' 44 | ios: true 45 | image_path: 'assets/images/app_icon.png' 46 | 47 | #Native splash 48 | json_serializable: ^6.7.0 49 | build_runner: ^2.4.5 50 | flutter_native_splash: ^2.3.1 51 | 52 | flutter_native_splash: 53 | android: true 54 | ios: true 55 | web: false 56 | background_image: 'assets/images/splash.png' 57 | 58 | flutter: 59 | uses-material-design: true 60 | 61 | assets: 62 | - assets/images/ 63 | - assets/lottie/ 64 | -------------------------------------------------------------------------------- /features/home/lib/src/ui/components/menu_title.dart: -------------------------------------------------------------------------------- 1 | import 'package:home/src/home.dart'; 2 | 3 | class HomeMenuTitle extends StatelessWidget { 4 | const HomeMenuTitle({ 5 | super.key, 6 | }); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Row( 11 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 12 | children: [ 13 | Padding( 14 | padding: const EdgeInsets.all( 15 | ApplicationPadding.PADDING_10, 16 | ), 17 | child: Text( 18 | StringConstant.restarants, 19 | style: AppFonts.normal18, 20 | ), 21 | ), 22 | TextButton( 23 | onPressed: () { 24 | //TODO: Add navigation 25 | }, 26 | child: Row( 27 | children: [ 28 | Text( 29 | StringConstant.all, 30 | style: AppFonts.bold16.copyWith( 31 | color: ApplicationColors.primaryButtonColor, 32 | ), 33 | ), 34 | const Icon( 35 | Icons.chevron_right_rounded, 36 | color: ApplicationColors.primaryButtonColor, 37 | ), 38 | ], 39 | ), 40 | ) 41 | ], 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /features/home/lib/src/ui/components/app_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:home/src/home.dart'; 2 | 3 | class AppSliverAppBar extends StatelessWidget { 4 | final Widget _child; 5 | 6 | const AppSliverAppBar({super.key, required Widget child}) : _child = child; 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | final Size size = MediaQuery.sizeOf(context); 11 | 12 | return SliverAppBar( 13 | centerTitle: false, 14 | shape: const RoundedRectangleBorder(), 15 | expandedHeight: size.height / ApplicationPadding.PADDING_4, 16 | flexibleSpace: FlexibleSpaceBar( 17 | centerTitle: false, 18 | background: Stack( 19 | children: [ 20 | Positioned.fill( 21 | child: _child, 22 | ), 23 | const Positioned( 24 | top: Dimensions.SIZE_120, 25 | left: Dimensions.SIZE_20, 26 | child: AppBarChip( 27 | label: StringConstant.overTwoHundredStarts, 28 | starts: Dimensions.SIZE_4, 29 | priority: StringConstant.good, 30 | ), 31 | ), 32 | ], 33 | ), 34 | ), 35 | title: Text( 36 | StringConstant.appName, 37 | style: AppFonts.normal24, 38 | ), 39 | floating: true, 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /features/home/lib/src/bloc/menu/menu_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/usecase/get_menu.dart'; 2 | import 'package:home/src/home.dart'; 3 | 4 | part 'menu_event.dart'; 5 | part 'menu_state.dart'; 6 | 7 | final class MenuBloc extends Bloc { 8 | final FetchMenuItemsUseCase _fetchMenuItemsUseCase; 9 | 10 | MenuBloc({ 11 | required FetchMenuItemsUseCase fetchMenuItemsUseCase, 12 | }) : _fetchMenuItemsUseCase = fetchMenuItemsUseCase, 13 | super(MenuState(menu: [])) { 14 | on(_onFetchMenuEvent); 15 | on(onChangeMenuItemSize); 16 | 17 | add(FetchMenuEvent()); 18 | } 19 | 20 | Future _onFetchMenuEvent( 21 | FetchMenuEvent event, 22 | Emitter emit, 23 | ) async { 24 | try { 25 | final List data = await _fetchMenuItemsUseCase(); 26 | emit(MenuState( 27 | menu: data, 28 | )); 29 | } catch (e) { 30 | throw (Exception()); 31 | } 32 | } 33 | 34 | Future onChangeMenuItemSize( 35 | ChangeMenuItemSizeEvent event, 36 | Emitter emit, 37 | ) async { 38 | emit(MenuState( 39 | menu: await _fetchMenuItemsUseCase(), 40 | isMenuAnimated: changeIsAnimatedState(), 41 | )); 42 | } 43 | 44 | bool changeIsAnimatedState() => state.isMenuAnimated = !state.isMenuAnimated; 45 | } 46 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /data/lib/repository_impl/admin/admin_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | import 'package:data/mapper/user.dart'; 3 | 4 | final class AdminRepositoryImpl implements AdminRepository { 5 | final RemoteAdminDataSource _remoteAdminDataSource; 6 | 7 | AdminRepositoryImpl({ 8 | required RemoteAdminDataSource remoteAdminDataSource, 9 | }) : _remoteAdminDataSource = remoteAdminDataSource; 10 | //TODO remove or do somehing 11 | @override 12 | Future deleteMultipleUsers() { 13 | // TODO: implement deleteMultipleUsers 14 | throw UnimplementedError(); 15 | } 16 | 17 | @override 18 | Future deleteUser() { 19 | // TODO: implement deleteUser 20 | throw UnimplementedError(); 21 | } 22 | 23 | @override 24 | Future> getUsersPerDay() { 25 | return _remoteAdminDataSource.getUsersPerDay(); 26 | } 27 | 28 | @override 29 | Future> getUsersByRegistrationDate() async { 30 | final List data = 31 | await _remoteAdminDataSource.getUsersByRegistrationDate(); 32 | return data.map(UserMapper.toEntity).toList(); 33 | } 34 | 35 | @override 36 | Future saveProductToFirebase(Product product, File imageFile) async { 37 | final ProductModel mappedProduct = ProductMapper.toModel(product); 38 | _remoteAdminDataSource.addProduct( 39 | mappedProduct, 40 | imageFile, 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /features/onboarding/lib/cubit/on_boarding_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:onboarding/onboarding.dart'; 2 | 3 | class OnBoardingCubit extends Cubit { 4 | final CacheFirstTimerUseCase _cacheFirstTimerUseCase; 5 | final CheckIfUserIsFirstTimerUseCase _checkIfUserIsFirstTimerUseCase; 6 | 7 | OnBoardingCubit({ 8 | required CacheFirstTimerUseCase cacheFirstTimer, 9 | required CheckIfUserIsFirstTimerUseCase checkIfUserIsFirstTimer, 10 | }) : _cacheFirstTimerUseCase = cacheFirstTimer, 11 | _checkIfUserIsFirstTimerUseCase = checkIfUserIsFirstTimer, 12 | super(true); 13 | 14 | Future cacheFirstTimer() async { 15 | final Either result = await _cacheFirstTimerUseCase(); 16 | 17 | result.fold( 18 | (failure) => null, 19 | (_) => null, 20 | ); 21 | } 22 | 23 | Future checkIfUserIsFirstTimer() async { 24 | final result = await _checkIfUserIsFirstTimerUseCase(); 25 | 26 | result.fold( 27 | (failure) => null, 28 | emit, 29 | ); 30 | } 31 | 32 | Future navigateToMain({required BuildContext context}) async { 33 | await AutoRouter.of(context).replace(DashBoardPage()); 34 | } 35 | 36 | Future navigateToAuthOrHome({required BuildContext context}) async { 37 | await AutoRouter.of(context).replace( 38 | FirebaseAuth.instance.currentUser == null 39 | ? SignInPage() 40 | : DashBoardPage(), 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /features/admin/lib/bloc/admin/admin_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:admin/admin.dart'; 4 | 5 | part 'admin_event.dart'; 6 | part 'admin_state.dart'; 7 | 8 | class AdminBloc extends Bloc { 9 | final ImagePicker _imagePicker; 10 | final SaveProductUseCase _saveProductUseCase; 11 | File? pickedImage; 12 | AdminBloc({ 13 | required ImagePicker imagePicker, 14 | required SaveProductUseCase saveProductUseCase, 15 | }) : _imagePicker = imagePicker, 16 | _saveProductUseCase = saveProductUseCase, 17 | super(AdminInitial()) { 18 | on(_onPickImageFromGallery); 19 | on(_onSaveProductEvent); 20 | } 21 | 22 | Future _onPickImageFromGallery( 23 | PickImageFromGalleryEvent event, 24 | Emitter emit, 25 | ) async { 26 | try { 27 | final XFile? xFile = await _imagePicker.pickImage( 28 | source: ImageSource.gallery, 29 | ); 30 | if (xFile == null) return; 31 | pickedImage = File(xFile.path); 32 | } catch (e) { 33 | emit(AdminFailedState(errorMessage: e.toString())); 34 | } 35 | } 36 | 37 | Future _onSaveProductEvent( 38 | SaveProductEvent event, 39 | Emitter emit, 40 | ) async { 41 | await _saveProductUseCase( 42 | event.product, 43 | pickedImage ?? 44 | File( 45 | StringConstant.emptyString, 46 | )); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /features/settings/lib/ui/components/user_avatar.dart: -------------------------------------------------------------------------------- 1 | import 'package:settings/settings.dart'; 2 | 3 | class UserAvatar extends StatelessWidget { 4 | const UserAvatar({ 5 | super.key, 6 | }); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return BlocBuilder( 11 | builder: (context, state) { 12 | return StreamBuilder( 13 | stream: state.currentUser, 14 | builder: (context, snapshot) { 15 | return CircleAvatar( 16 | backgroundColor: ApplicationColors.primaryButtonColor, 17 | maxRadius: Dimensions.SIZE_88, 18 | child: Padding( 19 | padding: const EdgeInsets.all( 20 | ApplicationPadding.PADDING_4, 21 | ), 22 | child: snapshot.data?.image == null 23 | ? const CircleAvatar( 24 | foregroundImage: AssetImage(ImagePaths.user), 25 | maxRadius: Dimensions.SIZE_88, 26 | ) 27 | : CircleAvatar( 28 | foregroundImage: NetworkImage( 29 | snapshot.data?.image ?? StringConstant.emptyString, 30 | ), 31 | maxRadius: Dimensions.SIZE_88, 32 | ), 33 | ), 34 | ); 35 | }); 36 | }, 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/lib/unit/domain/usecase/auth/sign_in_with_google_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:testing/test.dart'; 3 | 4 | class MockAuthRepository extends Mock implements AuthRepository {} 5 | 6 | void main() { 7 | late SignInWithGoogleUseCase signInWithGoogleUseCase; 8 | late AuthRepository authRepository; 9 | 10 | setUp( 11 | () { 12 | authRepository = MockAuthRepository(); 13 | signInWithGoogleUseCase = SignInWithGoogleUseCase(authRepository); 14 | }, 15 | ); 16 | 17 | SignInWithGoogleParams params = const SignInWithGoogleParams(); 18 | UserEntity user = UserEntity( 19 | registrationDate: Timestamp.now(), 20 | fullName: '', 21 | bio: '', 22 | uid: '1', 23 | emailIsVerified: false, 24 | image: 'sss', 25 | email: 'alidroid696@gmail.com', 26 | username: 'ali', 27 | ); 28 | 29 | test('should call the [AuthRepository.singIn()]', () async { 30 | //arrange 31 | when( 32 | () => authRepository.signInWithGoogle(), 33 | ).thenAnswer((_) async => Right(user)); 34 | 35 | //act 36 | final Either result = await signInWithGoogleUseCase(params); 37 | 38 | // assert 39 | expect( 40 | result, 41 | equals( 42 | Right(user), 43 | ), 44 | ); 45 | 46 | verify( 47 | () => authRepository.signInWithGoogle(), 48 | ).called(1); 49 | 50 | verifyNoMoreInteractions(authRepository); 51 | }); 52 | } 53 | -------------------------------------------------------------------------------- /features/card/lib/ui/components/empty_cart.dart: -------------------------------------------------------------------------------- 1 | import 'package:card/shopping_card.dart'; 2 | 3 | class EmptyCartBody extends StatelessWidget { 4 | const EmptyCartBody({ 5 | super.key, 6 | }); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | final Size size = MediaQuery.sizeOf(context); 11 | 12 | return Scaffold( 13 | appBar: AppBar( 14 | title: const Text( 15 | StringConstant.cart, 16 | ), 17 | ), 18 | body: Column( 19 | crossAxisAlignment: CrossAxisAlignment.stretch, 20 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 21 | children: [ 22 | SizedBox( 23 | height: size.height / Dimensions.SIZE_4, 24 | width: size.width / Dimensions.SIZE_2, 25 | child: Lottie.asset( 26 | animate: true, 27 | ImagePaths.emptyCart, 28 | repeat: true, 29 | 30 | ), 31 | ), 32 | Column( 33 | children: [ 34 | Text( 35 | StringConstant.notingIntoCartTitle, 36 | style: AppFonts.bold18, 37 | ), 38 | SizedBox( 39 | height: size.height / Dimensions.SIZE_20, 40 | ), 41 | const Text( 42 | StringConstant.nothingIntoCartSubtitle, 43 | textAlign: TextAlign.center, 44 | ) 45 | ], 46 | ) 47 | ], 48 | ), 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /data/lib/data_provider/settings/settings_remote_data_source_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | final class SettingsRemoteDataSourceImpl implements SettingsRemoteDataSource { 4 | final FirebaseStorage _firebaseStorage; 5 | final FirebaseFirestore _fireStore; 6 | 7 | SettingsRemoteDataSourceImpl({ 8 | required FirebaseStorage firebaseStorage, 9 | required FirebaseFirestore fireStore, 10 | }) : _firebaseStorage = firebaseStorage, 11 | _fireStore = fireStore; 12 | 13 | @override 14 | Future changeAvatar(File imageFile) async { 15 | final String id = const Uuid().v4(); 16 | 17 | final Reference storageReference = 18 | _firebaseStorage.ref().child('avatar/$id'); 19 | 20 | final UploadTask task = storageReference.putFile(imageFile); 21 | await task.whenComplete(() => debugPrint('Avatar Uploaded')); 22 | 23 | final String getUploadedImage = await storageReference.getDownloadURL(); 24 | 25 | final DocumentReference> docRef = _fireStore 26 | .collection(FirebaseEnum.users.name) 27 | .doc(FirebaseAuth.instance.currentUser?.uid); 28 | 29 | await docRef.update({'image': getUploadedImage}); 30 | 31 | if (getUploadedImage.startsWith('gs://') || 32 | getUploadedImage.startsWith('https://')) { 33 | return getUploadedImage; 34 | } 35 | 36 | final Reference ref = storageReference.storage.refFromURL(getUploadedImage); 37 | final String image = await ref.getDownloadURL(); 38 | 39 | return image; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/lib/unit/domain/usecase/auth/sign_up_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:testing/test.dart'; 3 | 4 | class MockAuthRepository extends Mock implements AuthRepository {} 5 | 6 | void main() { 7 | late SignUpUseCase signUpUseCase; 8 | late AuthRepository authRepository; 9 | 10 | setUp( 11 | () { 12 | authRepository = MockAuthRepository(); 13 | signUpUseCase = SignUpUseCase(authRepository); 14 | }, 15 | ); 16 | 17 | const SignUpParams params = SignUpParams( 18 | email: 'alidroid@gmail.com', 19 | fullName: 'Ali', 20 | password: '12345', 21 | ); 22 | 23 | test( 24 | 'should call the [AuthRepository.signUp]', 25 | () async { 26 | //arrange 27 | when( 28 | () => authRepository.signUp( 29 | email: any(named: 'email'), 30 | fullName: any(named: 'fullName'), 31 | password: any(named: 'password'), 32 | ), 33 | ).thenAnswer((_) async => const Right(null)); 34 | 35 | //act 36 | final Either result = await signUpUseCase(params); 37 | 38 | // assert 39 | expect( 40 | result, 41 | equals( 42 | const Right(null), 43 | ), 44 | ); 45 | 46 | verify( 47 | () => authRepository.signUp( 48 | email: params.email, 49 | fullName: params.fullName, 50 | password: params.password, 51 | ), 52 | ).called(1); 53 | 54 | verifyNoMoreInteractions(authRepository); 55 | }, 56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /core_ui/lib/components/app_theme_icon_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | class AppThemeIcon extends StatelessWidget { 4 | final VoidCallback _onTap; 5 | final bool _themeState; 6 | 7 | const AppThemeIcon({ 8 | required VoidCallback onTap, 9 | required bool themeState, 10 | super.key, 11 | }) : _onTap = onTap, 12 | _themeState = themeState; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | final Size size = MediaQuery.sizeOf(context); 17 | return IconButton( 18 | onPressed: _onTap, 19 | icon: _themeState 20 | ? Padding( 21 | padding: const EdgeInsets.symmetric( 22 | horizontal: ApplicationPadding.PADDING_14, 23 | ), 24 | child: SizedBox( 25 | height: size.height / Dimensions.SIZE_20, 26 | width: size.width / Dimensions.SIZE_14, 27 | child: Image.asset( 28 | color: ApplicationColors.white, 29 | ImagePaths.nightIcon, 30 | ), 31 | ), 32 | ) 33 | : Padding( 34 | padding: const EdgeInsets.symmetric( 35 | horizontal: ApplicationPadding.PADDING_14, 36 | ), 37 | child: Image.asset( 38 | color: ApplicationColors.black, 39 | height: size.height / Dimensions.SIZE_20, 40 | width: size.width / Dimensions.SIZE_14, 41 | ImagePaths.dayIcon, 42 | ), 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/lib/unit/domain/usecase/auth/sign_in_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:testing/test.dart'; 3 | 4 | class MockAuthRepository extends Mock implements AuthRepository {} 5 | 6 | void main() { 7 | late SignInUseCase signInUseCase; 8 | late AuthRepository authRepository; 9 | 10 | setUp( 11 | () { 12 | authRepository = MockAuthRepository(); 13 | signInUseCase = SignInUseCase(authRepository); 14 | }, 15 | ); 16 | SignInParams params = const SignInParams( 17 | email: 'alidroid@mgial.com', 18 | password: '123455', 19 | ); 20 | 21 | UserEntity user = UserEntity( 22 | registrationDate: Timestamp.now(), 23 | fullName: '', 24 | bio: '', 25 | uid: '1', 26 | emailIsVerified: false, 27 | image: 'sss', 28 | email: 'alidroid696@gmail.com', 29 | username: 'ali', 30 | ); 31 | 32 | test('should call the [AuthRepository.singIn()]', () async { 33 | //arrange 34 | when( 35 | () => authRepository.signIn( 36 | email: params.email, 37 | password: params.password, 38 | ), 39 | ).thenAnswer((_) async => Right(user)); 40 | 41 | //act 42 | final Either result = await signInUseCase(params); 43 | 44 | // assert 45 | expect( 46 | result, 47 | equals( 48 | Right(user), 49 | ), 50 | ); 51 | 52 | verify( 53 | () => authRepository.signIn( 54 | email: params.email, 55 | password: params.password, 56 | ), 57 | ).called(1); 58 | 59 | verifyNoMoreInteractions(authRepository); 60 | }); 61 | } 62 | -------------------------------------------------------------------------------- /features/home/lib/src/bloc/home/home_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:home/src/home.dart'; 2 | 3 | part 'home_event.dart'; 4 | part 'home_state.dart'; 5 | 6 | final class HomeBloc extends Bloc { 7 | final FetchProductsUseCase _getProductsUseCase; 8 | final Connection _connection; 9 | final AppRouter _router; 10 | 11 | HomeBloc( 12 | {required FetchProductsUseCase getProductsUseCase, 13 | required Connection connectionUseCase, 14 | required AppRouter router}) 15 | : _getProductsUseCase = getProductsUseCase, 16 | _connection = connectionUseCase, 17 | _router = router, 18 | super(InitialProductsState()) { 19 | on(_fetchProductsEvent); 20 | on(_onNavigateToProductDetailsScreen); 21 | add(FetchProductsEvent()); 22 | } 23 | 24 | Future _fetchProductsEvent( 25 | FetchProductsEvent event, 26 | Emitter emit, 27 | ) async { 28 | if (!await _connection.isConnected()) { 29 | emit(NoInternetConnectionState()); 30 | } 31 | emit(LoadingProductsState()); 32 | try { 33 | final List data = await _getProductsUseCase(); 34 | emit( 35 | LoadedProductsState(products: data), 36 | ); 37 | } catch (e) { 38 | emit( 39 | ErrorProductsState(error: StringConstants.stateError), 40 | ); 41 | } 42 | } 43 | 44 | void _onNavigateToProductDetailsScreen( 45 | NavigateToProductDetailsScreenEvent event, 46 | Emitter emit, 47 | ) { 48 | _router.push( 49 | DetailsPage(productId: event.productId), 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /core/lib/core.dart: -------------------------------------------------------------------------------- 1 | library core; 2 | 3 | export 'package:bloc/bloc.dart'; 4 | export 'package:cloud_firestore/cloud_firestore.dart'; 5 | export 'package:core/constants/api.dart'; 6 | export 'package:core/constants/connection.dart'; 7 | export 'package:core/constants/string_constants.dart'; 8 | export 'package:core/di/di.dart'; 9 | export 'package:core/di/firebase_options.dart'; 10 | export 'package:core/enums/hero_tags.dart'; 11 | export 'package:core/enums/locale.dart'; 12 | export 'package:core/enums/user_update_action.dart'; 13 | export 'package:core/exceptions/failure.dart'; 14 | export 'package:core/exceptions/url_launcher.dart'; 15 | export 'package:core/extensions/context.dart'; 16 | export 'package:core/services/connection/connection.dart'; 17 | export 'package:core/services/url_laucher/url_laucher.dart'; 18 | export 'package:core/usecase/usecase.dart'; 19 | export 'package:core/utils/typedefs.dart'; 20 | export 'package:dartz/dartz.dart' hide Order, State, Task; 21 | export 'package:equatable/equatable.dart'; 22 | export 'package:firebase_auth/firebase_auth.dart'; 23 | export 'package:firebase_core/firebase_core.dart'; 24 | export 'package:firebase_storage/firebase_storage.dart'; 25 | export 'package:flutter_bloc/flutter_bloc.dart'; 26 | export 'package:get_it/get_it.dart'; 27 | export 'package:google_sign_in/google_sign_in.dart'; 28 | export 'package:hive_flutter/hive_flutter.dart'; 29 | export 'package:image_picker/image_picker.dart'; 30 | export 'package:internet_connection_checker/internet_connection_checker.dart'; 31 | export 'package:intl/intl.dart' hide TextDirection; 32 | export 'package:provider/provider.dart'; 33 | export 'package:url_launcher/url_launcher.dart'; 34 | export 'package:uuid/uuid.dart'; 35 | -------------------------------------------------------------------------------- /data/lib/model/user.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | part 'user.g.dart'; 4 | 5 | @JsonSerializable() 6 | final class UserModel extends Equatable { 7 | final String email; 8 | final String uid; 9 | final String? bio; 10 | final String fullName; 11 | final bool? emailIsVerified; 12 | final String? image; 13 | final String username; 14 | final Timestamp registrationDate; 15 | 16 | const UserModel({ 17 | required this.registrationDate, 18 | required this.fullName, 19 | required this.bio, 20 | required this.uid, 21 | required this.emailIsVerified, 22 | required this.image, 23 | required this.email, 24 | required this.username, 25 | }); 26 | 27 | UserModel.empty() 28 | : this( 29 | registrationDate: Timestamp.now(), 30 | emailIsVerified: true, 31 | image: '', 32 | username: '', 33 | uid: '', 34 | email: '', 35 | fullName: '', 36 | bio: '', 37 | ); 38 | 39 | factory UserModel.fromJson(Map json) { 40 | return _$UserModelFromJson(json); 41 | } 42 | 43 | DataMap toMap() => { 44 | 'uid': uid, 45 | 'email': email, 46 | 'fullName': fullName, 47 | 'image': image, 48 | 'bio': bio, 49 | 'username': username, 50 | 'emailIsVerified': emailIsVerified, 51 | 'registrationDate': registrationDate 52 | }; 53 | 54 | @override 55 | List get props => [ 56 | username, 57 | image, 58 | email, 59 | emailIsVerified, 60 | uid, 61 | fullName, 62 | bio, 63 | registrationDate, 64 | ]; 65 | } 66 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /core_ui/lib/components/cached_network_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:core_ui/core_ui.dart'; 2 | 3 | class AppCachedNetworkImage extends StatelessWidget { 4 | final String _url; 5 | 6 | const AppCachedNetworkImage({ 7 | super.key, 8 | required String url, 9 | }) : _url = url; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return CachedNetworkImage( 14 | useOldImageOnUrlChange: true, 15 | fit: BoxFit.fill, 16 | fadeInCurve: Curves.bounceIn, 17 | imageUrl: _url, 18 | filterQuality: FilterQuality.high, 19 | imageBuilder: ( 20 | BuildContext context, 21 | ImageProvider imageProvider, 22 | ) => 23 | Container( 24 | decoration: BoxDecoration( 25 | image: DecorationImage( 26 | image: imageProvider, 27 | fit: BoxFit.fitHeight, 28 | isAntiAlias: true, 29 | ), 30 | borderRadius: BorderRadius.circular( 31 | Dimensions.SIZE_10, 32 | ), 33 | ), 34 | ), 35 | placeholder: ( 36 | BuildContext context, 37 | String url, 38 | ) => 39 | SpinKitFadingCircle( 40 | itemBuilder: ( 41 | BuildContext context, 42 | int index, 43 | ) { 44 | return DecoratedBox( 45 | decoration: BoxDecoration( 46 | color: index.isEven 47 | ? ApplicationColors.red 48 | : ApplicationColors.green, 49 | ), 50 | ); 51 | }, 52 | ), 53 | errorWidget: ( 54 | BuildContext context, 55 | String url, 56 | error, 57 | ) => 58 | AppIcons.error, 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /features/home/lib/src/ui/components/search_text_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:home/src/home.dart'; 2 | 3 | class SearchTextField extends StatelessWidget { 4 | final String _labelText; 5 | final TextEditingController _controller; 6 | 7 | const SearchTextField({ 8 | super.key, 9 | required String labelText, 10 | required TextEditingController textEditingController, 11 | }) : _labelText = labelText, 12 | _controller = textEditingController; 13 | 14 | @override 15 | Widget build( 16 | BuildContext context, 17 | ) { 18 | final Size size = MediaQuery.sizeOf(context); 19 | return SizedBox( 20 | height: size.height / Dimensions.SIZE_16, 21 | child: Card( 22 | shape: const RoundedRectangleBorder( 23 | borderRadius: BorderRadius.all( 24 | Radius.circular( 25 | ApplicationPadding.PADDING_16, 26 | ), 27 | ), 28 | ), 29 | elevation: Dimensions.SIZE_8, 30 | child: Padding( 31 | padding: const EdgeInsets.symmetric( 32 | horizontal: ApplicationPadding.PADDING_16, 33 | ), 34 | child: TextField( 35 | style: AppFonts.normal14, 36 | controller: _controller, 37 | decoration: InputDecoration( 38 | border: InputBorder.none, 39 | contentPadding: const EdgeInsets.symmetric( 40 | vertical: ApplicationPadding.PADDING_16, 41 | ), 42 | suffix: const Icon( 43 | Icons.search_outlined, 44 | ), 45 | hintText: _labelText, 46 | hintStyle: AppFonts.normal14, 47 | ), 48 | ), 49 | ), 50 | ), 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /features/home/lib/src/home.dart: -------------------------------------------------------------------------------- 1 | export 'dart:async'; 2 | 3 | export 'package:core/constants/string_constants.dart'; 4 | export 'package:core/core.dart'; 5 | export 'package:core/di/di.dart'; 6 | export 'package:core/enums/currency.dart'; 7 | export 'package:core/enums/duration.dart'; 8 | export 'package:core/enums/weight.dart'; 9 | export 'package:core/extensions/string.dart'; 10 | export 'package:core_ui/components/cached_network_image.dart'; 11 | export 'package:core_ui/constants/image_path.dart'; 12 | export 'package:core_ui/constants/string.dart'; 13 | export 'package:core_ui/constants/widget.dart'; 14 | export 'package:core_ui/core_ui.dart'; 15 | export 'package:core_ui/resources/app_colors.dart'; 16 | export 'package:core_ui/resources/app_dimension.dart'; 17 | export 'package:core_ui/resources/app_fonts.dart'; 18 | export 'package:core_ui/resources/app_icons.dart'; 19 | export 'package:domain/domain.dart'; 20 | export 'package:domain/usecase/product/get_products.dart'; 21 | export 'package:flutter/material.dart'; 22 | export 'package:home/src/bloc/home/home_bloc.dart'; 23 | export 'package:home/src/ui/components/app_bar.dart'; 24 | export 'package:home/src/ui/components/app_bar_chip.dart'; 25 | export 'package:home/src/ui/components/card.dart'; 26 | export 'package:home/src/ui/components/home_content.dart'; 27 | export 'package:home/src/ui/components/home_shadow.dart'; 28 | export 'package:home/src/ui/components/home_title.dart'; 29 | export 'package:home/src/ui/components/search_text_field.dart'; 30 | export 'package:home/src/ui/components/sliver_list.dart'; 31 | export 'package:home/src/ui/screen/home_page.dart'; 32 | export 'package:navigation/navigation.dart'; 33 | export 'package:navigation/navigation/app_router.dart'; 34 | export 'package:product_details/product_details.dart'; 35 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 14 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "733275854742", 4 | "project_id": "innofire-ccce6", 5 | "storage_bucket": "innofire-ccce6.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:733275854742:android:2dd37be01cca1cda652fb7", 11 | "android_client_info": { 12 | "package_name": "com.example.amazon_prime" 13 | } 14 | }, 15 | "oauth_client": [ 16 | { 17 | "client_id": "733275854742-0sa1u9simslelh017f5dupv10muig5hk.apps.googleusercontent.com", 18 | "client_type": 1, 19 | "android_info": { 20 | "package_name": "com.example.amazon_prime", 21 | "certificate_hash": "19370df35eb82e9b91c60772a7b9da3230c13e5e" 22 | } 23 | }, 24 | { 25 | "client_id": "733275854742-rvu0he0uptpdme4tcbufn1ko385dup8q.apps.googleusercontent.com", 26 | "client_type": 3 27 | } 28 | ], 29 | "api_key": [ 30 | { 31 | "current_key": "AIzaSyAs71FIyGxVF-Lc8LTNp1NlDbPRc67aK6U" 32 | } 33 | ], 34 | "services": { 35 | "appinvite_service": { 36 | "other_platform_oauth_client": [ 37 | { 38 | "client_id": "733275854742-pqj8ot4pj5m8fgef06uk9h58376mesl7.apps.googleusercontent.com", 39 | "client_type": 3 40 | }, 41 | { 42 | "client_id": "733275854742-ug8aq40d52v3s4dih2s799m7qng57spg.apps.googleusercontent.com", 43 | "client_type": 2, 44 | "ios_info": { 45 | "bundle_id": "com.example.amazonPrime" 46 | } 47 | } 48 | ] 49 | } 50 | } 51 | } 52 | ], 53 | "configuration_version": "1" 54 | } -------------------------------------------------------------------------------- /pub_get_script.sh: -------------------------------------------------------------------------------- 1 | 2 | printf "core pub get\n" 3 | cd core || exit 4 | flutter clean && flutter clean cache && flutter pub get 5 | cd .. 6 | printf '\n\n' 7 | 8 | printf "core_ui pub get\n" 9 | cd core_ui || exit 10 | flutter clean && flutter clean cache && flutter pub get 11 | cd .. 12 | printf '\n\n' 13 | 14 | printf "test pub get\n" 15 | cd test || exit 16 | flutter clean && flutter clean cache && flutter pub get 17 | cd .. 18 | printf '\n\n' 19 | 20 | printf "data pub get\n" 21 | cd data || exit 22 | flutter clean && flutter clean cache && flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs 23 | cd .. 24 | printf '\n\n' 25 | 26 | printf "domain pub get\n" 27 | cd domain || exit 28 | flutter clean && flutter clean cache && flutter pub get 29 | cd .. 30 | printf '\n\n' 31 | 32 | printf "navigation pub get\n" 33 | cd navigation || exit 34 | flutter clean && flutter clean cache && flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs 35 | cd .. 36 | printf '\n\n' 37 | 38 | printf "auth pub get\n" 39 | cd features/auth || exit 40 | flutter clean && flutter clean cache && flutter pub get 41 | cd ../.. 42 | printf '\n\n' 43 | 44 | printf "home pub get\n" 45 | cd features/home || exit 46 | flutter clean && flutter clean cache && flutter pub get 47 | cd ../.. 48 | printf '\n\n' 49 | 50 | printf "product details pub get\n" 51 | cd features/product_details || exit 52 | flutter clean && flutter clean cache && flutter pub get 53 | cd ../.. 54 | printf '\n\n' 55 | 56 | printf "order pub get\n" 57 | cd features/order || exit 58 | flutter clean && flutter clean cache && flutter pub get 59 | cd ../.. 60 | printf '\n\n' 61 | 62 | printf "settings pub get\n" 63 | cd features/settings || exit 64 | flutter clean && flutter clean cache && flutter pub get 65 | cd ../.. 66 | printf '\n\n' 67 | -------------------------------------------------------------------------------- /features/auth/lib/bloc/auth_event.dart: -------------------------------------------------------------------------------- 1 | part of 'auth_bloc.dart'; 2 | 3 | abstract class AuthEvent extends Equatable { 4 | const AuthEvent(); 5 | } 6 | 7 | class SignInEvent extends AuthEvent { 8 | const SignInEvent({ 9 | required this.email, 10 | required this.password, 11 | }); 12 | 13 | final String email; 14 | final String password; 15 | 16 | @override 17 | List get props => [ 18 | email, 19 | password, 20 | ]; 21 | } 22 | 23 | class SignUpEvent extends AuthEvent { 24 | const SignUpEvent({ 25 | required this.email, 26 | required this.password, 27 | required this.name, 28 | }); 29 | 30 | final String email; 31 | final String password; 32 | final String name; 33 | 34 | @override 35 | List get props => [ 36 | email, 37 | password, 38 | name, 39 | ]; 40 | } 41 | 42 | class SignInAsAdminEvent extends AuthEvent { 43 | @override 44 | List get props => []; 45 | } 46 | 47 | class ForgotPasswordEvent extends AuthEvent { 48 | const ForgotPasswordEvent({ 49 | required this.email, 50 | }); 51 | 52 | final String email; 53 | 54 | @override 55 | List get props => [ 56 | email, 57 | ]; 58 | } 59 | 60 | final class NavigateToRegistrationPageEvent extends AuthEvent { 61 | @override 62 | List get props => []; 63 | } 64 | 65 | final class NavigateTosSignInPageEvent extends AuthEvent { 66 | @override 67 | List get props => []; 68 | } 69 | 70 | final class NavigateTosHomePageEvent extends AuthEvent { 71 | @override 72 | List get props => []; 73 | } 74 | 75 | final class SignInWithGoogleEvent extends AuthEvent { 76 | @override 77 | List get props => []; 78 | } 79 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled. 5 | 6 | version: 7 | revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 17 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 18 | - platform: android 19 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 20 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 21 | - platform: ios 22 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 23 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 24 | - platform: linux 25 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 26 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 27 | - platform: macos 28 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 29 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 30 | - platform: web 31 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 32 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 33 | - platform: windows 34 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 35 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /features/auth/lib/components/sign_in_form.dart: -------------------------------------------------------------------------------- 1 | import 'package:auth/auth.dart'; 2 | 3 | class SignInForm extends StatefulWidget { 4 | const SignInForm({ 5 | required this.emailController, 6 | required this.passwordController, 7 | required this.formKey, 8 | super.key, 9 | }); 10 | 11 | final TextEditingController emailController; 12 | final TextEditingController passwordController; 13 | final GlobalKey formKey; 14 | 15 | @override 16 | State createState() => _SignInFormState(); 17 | } 18 | 19 | class _SignInFormState extends State { 20 | bool obscurePassword = true; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Form( 25 | key: widget.formKey, 26 | child: Column( 27 | children: [ 28 | AppTextField( 29 | controller: widget.emailController, 30 | hintText: StringConstant.emailAddress, 31 | keyboardType: TextInputType.emailAddress, 32 | ), 33 | const SizedBox( 34 | height: Dimensions.SIZE_20, 35 | ), 36 | AppTextField( 37 | maxLines: Dimensions.SIZE_1.toInt(), 38 | controller: widget.passwordController, 39 | hintText: StringConstant.password, 40 | obscureText: obscurePassword, 41 | keyboardType: TextInputType.visiblePassword, 42 | suffixIcon: IconButton( 43 | onPressed: () { 44 | setState(() { 45 | obscurePassword = !obscurePassword; 46 | }); 47 | }, 48 | icon: Icon( 49 | obscurePassword ? Icons.remove_red_eye : Icons.hide_source, 50 | color: ApplicationColors.disabledColor, 51 | ), 52 | ), 53 | ), 54 | ], 55 | ), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /data/lib/repository_impl/product/product_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/data.dart'; 2 | 3 | final class ProductRepositoryImpl implements ProductRepository { 4 | final RemoteDataSource _remoteDataSource; 5 | final Connection _connection; 6 | final LocaleDataSource _localeDataSource; 7 | ProductRepositoryImpl( 8 | RemoteDataSource remoteDataSource, 9 | Connection connection, 10 | LocaleDataSource localeDataSource, 11 | ) : _remoteDataSource = remoteDataSource, 12 | _connection = connection, 13 | _localeDataSource = localeDataSource; 14 | 15 | @override 16 | Future> fetchProducts() async { 17 | final Box productsBox = Hive.box(LocaleStorage.products.name); 18 | if (await _connection.isConnected()) { 19 | final List data = await _remoteDataSource.getProducts(); 20 | if (productsBox.isNotEmpty) { 21 | productsBox.clear(); 22 | } 23 | await _localeDataSource.addProducts(data); 24 | 25 | return data.map(ProductMapper.toEntity).toList().cast(); 26 | } else { 27 | final List data = _localeDataSource.getAllProducts(); 28 | return data.map(ProductMapper.toEntity).toList().cast(); 29 | } 30 | } 31 | 32 | @override 33 | Future fetchProductById(int productId) async { 34 | if (await _connection.isConnected()) { 35 | final ProductModel data = 36 | await _remoteDataSource.getProductsById(productId); 37 | return ProductMapper.toEntity(data); 38 | } else { 39 | final ProductModel data = 40 | await _localeDataSource.getProductById(productId); 41 | return ProductMapper.toEntity(data); 42 | } 43 | } 44 | 45 | @override 46 | Future> fetchMenu() async { 47 | final List data = await _remoteDataSource.getMenu(); 48 | return data.map(MenuMapper.toEntity).toList().cast(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Amazon Prime 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | amazon_prime 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | CADisableMinimumFrameDurationOnPhone 47 | 48 | UIApplicationSupportsIndirectInputEvents 49 | 50 | UIStatusBarHidden 51 | 52 | 53 | 54 | --------------------------------------------------------------------------------