├── movie_hub ├── linux │ ├── .gitignore │ ├── main.cc │ ├── flutter │ │ ├── generated_plugin_registrant.h │ │ ├── generated_plugin_registrant.cc │ │ └── generated_plugins.cmake │ └── my_application.h ├── lib │ ├── features │ │ ├── splash │ │ │ └── splash.dart │ │ ├── movies │ │ │ ├── watch_movies │ │ │ │ ├── watch_movies.dart │ │ │ │ └── presentation │ │ │ │ │ └── watch_movies_view.dart │ │ │ ├── shared_widgets │ │ │ │ ├── widgets.dart │ │ │ │ ├── movies_grid.dart │ │ │ │ └── movie_card_tile.dart │ │ │ ├── nav_bar │ │ │ │ ├── nav_bar.dart │ │ │ │ ├── nav_bar_locator.dart │ │ │ │ └── change_notifier │ │ │ │ │ └── nav_bar_notifier.dart │ │ │ ├── discover │ │ │ │ ├── data │ │ │ │ │ ├── model │ │ │ │ │ │ └── search_params_model.dart │ │ │ │ │ ├── datasource │ │ │ │ │ │ └── remote_data_source.dart │ │ │ │ │ └── repo_impl │ │ │ │ │ │ └── search_movies_repository_impl.dart │ │ │ │ ├── domain │ │ │ │ │ ├── repository │ │ │ │ │ │ └── search_movies_repository.dart │ │ │ │ │ └── usecase │ │ │ │ │ │ ├── search_movies_usecase.dart │ │ │ │ │ │ └── discover_movies_usecase.dart │ │ │ │ ├── presentation │ │ │ │ │ ├── atoms │ │ │ │ │ │ └── movie_not_found.dart │ │ │ │ │ ├── views │ │ │ │ │ │ └── search_view.dart │ │ │ │ │ ├── notifier │ │ │ │ │ │ └── discover_movies_notifier.dart │ │ │ │ │ └── components │ │ │ │ │ │ └── search_movies_grid.dart │ │ │ │ ├── search_movies.dart │ │ │ │ └── search_locator.dart │ │ │ ├── movie_dashboard.dart │ │ │ ├── watchlist │ │ │ │ ├── domain │ │ │ │ │ ├── repo │ │ │ │ │ │ └── watch_list_repo.dart │ │ │ │ │ └── usecase │ │ │ │ │ │ ├── get_watchlist_movie_id_usecase.dart │ │ │ │ │ │ ├── add_to_watchlist_usecase.dart │ │ │ │ │ │ └── remove_from_watch_list_usecase.dart │ │ │ │ ├── watchlist.dart │ │ │ │ └── presentation │ │ │ │ │ └── notifier │ │ │ │ │ ├── get_watch_list_movie_id_notifier.dart │ │ │ │ │ └── watchlist_movie_details_notifier.dart │ │ │ ├── home │ │ │ │ ├── domain │ │ │ │ │ ├── usecases │ │ │ │ │ │ ├── get_popular_movies_usecase.dart │ │ │ │ │ │ ├── get_top_rated_movies_usecase.dart │ │ │ │ │ │ ├── get_upcoming_movies_usecase.dart │ │ │ │ │ │ └── get_trending_movies_usecase.dart │ │ │ │ │ └── repository │ │ │ │ │ │ └── home_repository.dart │ │ │ │ ├── data │ │ │ │ │ ├── models │ │ │ │ │ │ └── see_all_params.dart │ │ │ │ │ └── datasource │ │ │ │ │ │ └── home_remote_data_source.dart │ │ │ │ ├── presentation │ │ │ │ │ ├── atoms │ │ │ │ │ │ ├── shimmer.dart │ │ │ │ │ │ ├── upcoming_movies_section.dart │ │ │ │ │ │ ├── trending_for_the_day.dart │ │ │ │ │ │ ├── top_rated_movies_section.dart │ │ │ │ │ │ ├── popular_movies_section.dart │ │ │ │ │ │ └── trending_for_the_week_section.dart │ │ │ │ │ ├── notifier │ │ │ │ │ │ ├── popular_movies_notifier.dart │ │ │ │ │ │ ├── upcoming_movies_notifier.dart │ │ │ │ │ │ ├── top_rated_movies_notifier.dart │ │ │ │ │ │ ├── trending_movies_notifier.dart │ │ │ │ │ │ └── trending_for_the_week_notifier.dart │ │ │ │ │ └── components │ │ │ │ │ │ └── see_all_movies.dart │ │ │ │ └── home.dart │ │ │ └── movie_details │ │ │ │ ├── domain │ │ │ │ ├── usecase │ │ │ │ │ ├── get_similar_movies_usecase.dart │ │ │ │ │ ├── get_movie_detail_usecase.dart │ │ │ │ │ ├── get_images_usecase.dart │ │ │ │ │ └── is_movie_a_watchlist_usecase.dart │ │ │ │ ├── repo │ │ │ │ │ └── movie_detail_repo.dart │ │ │ │ └── entities │ │ │ │ │ └── image_entity.dart │ │ │ │ ├── presentation │ │ │ │ ├── atoms │ │ │ │ │ ├── watch_movie_button.dart │ │ │ │ │ ├── grid_view.dart │ │ │ │ │ └── similar_movies.dart │ │ │ │ ├── components │ │ │ │ │ ├── image_preview_page.dart │ │ │ │ │ └── movie_info.dart │ │ │ │ └── notifier │ │ │ │ │ ├── image_notifier.dart │ │ │ │ │ ├── similar_movies_notifier.dart │ │ │ │ │ └── movie_details_notifier.dart │ │ │ │ ├── movie_details.dart │ │ │ │ └── data │ │ │ │ └── model │ │ │ │ └── image_model.dart │ │ ├── auth │ │ │ ├── data │ │ │ │ └── model │ │ │ │ │ ├── auth_result_model.dart │ │ │ │ │ └── sign_up_params_model.dart │ │ │ ├── domain │ │ │ │ ├── entity │ │ │ │ │ ├── user_entity.dart │ │ │ │ │ └── auth_result_entity.dart │ │ │ │ ├── usecases │ │ │ │ │ ├── log_out_usecase.dart │ │ │ │ │ ├── check_log_in_status_usecase.dart │ │ │ │ │ ├── forgot_password_usecase.dart │ │ │ │ │ ├── sign_up_usecase.dart │ │ │ │ │ └── log_in_usecase.dart │ │ │ │ └── repository │ │ │ │ │ └── auth_repository.dart │ │ │ ├── auth.dart │ │ │ └── auth_locator.dart │ │ └── profile │ │ │ ├── data │ │ │ ├── model │ │ │ │ ├── base_model.dart │ │ │ │ └── user_details_model.dart │ │ │ └── repo-impl │ │ │ │ └── profile_repo_impl.dart │ │ │ ├── domain │ │ │ ├── entity │ │ │ │ ├── base_entity.dart │ │ │ │ └── user_details_entity.dart │ │ │ ├── repository │ │ │ │ └── profile_repo.dart │ │ │ └── usecase │ │ │ │ ├── update_avatar_usecase.dart │ │ │ │ ├── fetch_avatars.dart │ │ │ │ └── fetch_profile_details_usecase.dart │ │ │ ├── profile.dart │ │ │ ├── presentation │ │ │ ├── atoms │ │ │ │ └── action_list_tile.dart │ │ │ └── notifier │ │ │ │ ├── fetch_avatars_notifier.dart │ │ │ │ ├── fetch_profile_details_notifier.dart │ │ │ │ └── update_avatar_notifier.dart │ │ │ └── profile_locator.dart │ ├── app │ │ ├── app.dart │ │ ├── my_app.dart │ │ └── locator.dart │ ├── cores │ │ ├── errors │ │ │ ├── errors.dart │ │ │ ├── error_text.dart │ │ │ └── failures.dart │ │ ├── usecase │ │ │ ├── no_param.dart │ │ │ ├── usecase.dart │ │ │ └── usecase_interface.dart │ │ ├── utils │ │ │ ├── exception │ │ │ │ ├── exception.dart │ │ │ │ ├── base_exception.dart │ │ │ │ └── firebase_auth_exception.dart │ │ │ ├── type_defs.dart │ │ │ ├── logger.dart │ │ │ ├── utils.dart │ │ │ ├── setup.dart │ │ │ ├── precache_images.dart │ │ │ ├── firebase_helper.dart │ │ │ └── sizer.dart │ │ ├── navigator │ │ │ ├── navigator.dart │ │ │ ├── error_route.dart │ │ │ └── app_router.dart │ │ ├── constants │ │ │ ├── constants.dart │ │ │ ├── palette.dart │ │ │ ├── error_text.dart │ │ │ ├── font_size.dart │ │ │ └── asset.dart │ │ ├── cores.dart │ │ └── shared │ │ │ ├── shared.dart │ │ │ ├── loading_widget.dart │ │ │ ├── retry_button_widget.dart │ │ │ ├── error_widget.dart │ │ │ ├── cached_network_image_widget.dart │ │ │ └── app_bar_widget.dart │ └── main.dart ├── ios │ ├── 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 │ │ ├── AppDelegate.swift │ │ ├── GoogleService-Info.plist │ │ ├── Base.lproj │ │ │ └── Main.storyboard │ │ └── Info.plist │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.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 │ ├── .gitignore │ └── Podfile ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ ├── Icon-512.png │ │ ├── Icon-maskable-192.png │ │ └── Icon-maskable-512.png │ └── manifest.json ├── assets │ ├── icons │ │ ├── app_icon.png │ │ ├── profile.png │ │ ├── check.svg │ │ ├── arrow.svg │ │ ├── search.svg │ │ ├── eye.svg │ │ ├── user.svg │ │ ├── add.svg │ │ ├── home.svg │ │ ├── watch_list.svg │ │ ├── eye_close.svg │ │ ├── sign_out.svg │ │ ├── add_avatar.svg │ │ ├── person.svg │ │ └── mail.svg │ └── fonts │ │ ├── Montserrat-Bold.ttf │ │ ├── Montserrat-Light.ttf │ │ ├── Montserrat-Medium.ttf │ │ ├── Montserrat-Regular.ttf │ │ ├── Sacramento-Regular.ttf │ │ ├── Montserrat-ExtraBold.ttf │ │ ├── Montserrat-SemiBold.ttf │ │ ├── PlayfairDisplaySC-Bold.ttf │ │ └── PlayfairDisplaySC-BoldItalic.ttf ├── android │ ├── gradle.properties │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── 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 │ │ │ │ │ ├── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── values-night │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values │ │ │ │ │ │ └── styles.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── example │ │ │ │ │ │ └── movie_hub │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ ├── java │ │ │ │ │ └── io │ │ │ │ │ │ └── flutter │ │ │ │ │ │ └── app │ │ │ │ │ │ └── FlutterMultiDexApplication.java │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── google-services.json │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── settings.gradle │ └── build.gradle ├── macos │ ├── Runner │ │ ├── Configs │ │ │ ├── Debug.xcconfig │ │ │ ├── Release.xcconfig │ │ │ ├── Warnings.xcconfig │ │ │ └── AppInfo.xcconfig │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ ├── app_icon_1024.png │ │ │ │ ├── app_icon_128.png │ │ │ │ ├── app_icon_16.png │ │ │ │ ├── app_icon_256.png │ │ │ │ ├── app_icon_32.png │ │ │ │ ├── app_icon_512.png │ │ │ │ ├── app_icon_64.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Release.entitlements │ │ ├── DebugProfile.entitlements │ │ ├── MainFlutterWindow.swift │ │ └── Info.plist │ ├── .gitignore │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── Runner.xcodeproj │ │ └── project.xcworkspace │ │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── Podfile ├── windows │ ├── runner │ │ ├── resources │ │ │ └── app_icon.ico │ │ ├── resource.h │ │ ├── utils.h │ │ ├── runner.exe.manifest │ │ ├── flutter_window.h │ │ ├── main.cpp │ │ ├── CMakeLists.txt │ │ └── utils.cpp │ ├── .gitignore │ └── flutter │ │ ├── generated_plugin_registrant.h │ │ ├── generated_plugins.cmake │ │ └── generated_plugin_registrant.cc ├── README.md ├── .gitignore ├── analysis_options.yaml └── .metadata ├── .DS_Store ├── .idea ├── .gitignore ├── vcs.xml ├── modules.xml └── libraries │ └── Dart_SDK.xml └── .vscode ├── settings.json └── launch.json /movie_hub/linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /movie_hub/lib/features/splash/splash.dart: -------------------------------------------------------------------------------- 1 | export 'splash_page.dart'; -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/.DS_Store -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /movie_hub/lib/app/app.dart: -------------------------------------------------------------------------------- 1 | export 'locator.dart'; 2 | export 'my_app.dart'; -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/errors/errors.dart: -------------------------------------------------------------------------------- 1 | export 'failures.dart'; 2 | export 'error_text.dart'; -------------------------------------------------------------------------------- /movie_hub/lib/cores/usecase/no_param.dart: -------------------------------------------------------------------------------- 1 | class NoParams { 2 | const NoParams(); 3 | } 4 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/usecase/usecase.dart: -------------------------------------------------------------------------------- 1 | export 'usecase_interface.dart'; 2 | export 'no_param.dart'; -------------------------------------------------------------------------------- /movie_hub/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/web/favicon.png -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/watch_movies/watch_movies.dart: -------------------------------------------------------------------------------- 1 | export 'presentation/watch_movies_view.dart'; -------------------------------------------------------------------------------- /movie_hub/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/web/icons/Icon-192.png -------------------------------------------------------------------------------- /movie_hub/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/web/icons/Icon-512.png -------------------------------------------------------------------------------- /movie_hub/assets/icons/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/assets/icons/app_icon.png -------------------------------------------------------------------------------- /movie_hub/assets/icons/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/assets/icons/profile.png -------------------------------------------------------------------------------- /movie_hub/lib/cores/utils/exception/exception.dart: -------------------------------------------------------------------------------- 1 | export 'base_exception.dart'; 2 | export 'firebase_auth_exception.dart'; 3 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/shared_widgets/widgets.dart: -------------------------------------------------------------------------------- 1 | export 'genre_card_widget.dart'; 2 | export 'movie_card_tile.dart'; -------------------------------------------------------------------------------- /movie_hub/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/utils/type_defs.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | /// Map 4 | /// 5 | typedef Mapped = Map; 6 | -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Cupertino", 4 | "precache" 5 | ] 6 | } -------------------------------------------------------------------------------- /movie_hub/assets/fonts/Montserrat-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/assets/fonts/Montserrat-Bold.ttf -------------------------------------------------------------------------------- /movie_hub/lib/cores/navigator/navigator.dart: -------------------------------------------------------------------------------- 1 | export 'app_router.dart'; 2 | export 'route_generator.dart'; 3 | export 'error_route.dart'; -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /movie_hub/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /movie_hub/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /movie_hub/assets/fonts/Montserrat-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/assets/fonts/Montserrat-Light.ttf -------------------------------------------------------------------------------- /movie_hub/assets/fonts/Montserrat-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/assets/fonts/Montserrat-Medium.ttf -------------------------------------------------------------------------------- /movie_hub/assets/fonts/Montserrat-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/assets/fonts/Montserrat-Regular.ttf -------------------------------------------------------------------------------- /movie_hub/assets/fonts/Sacramento-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/assets/fonts/Sacramento-Regular.ttf -------------------------------------------------------------------------------- /movie_hub/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /movie_hub/assets/fonts/Montserrat-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/assets/fonts/Montserrat-ExtraBold.ttf -------------------------------------------------------------------------------- /movie_hub/assets/fonts/Montserrat-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/assets/fonts/Montserrat-SemiBold.ttf -------------------------------------------------------------------------------- /movie_hub/windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /movie_hub/assets/fonts/PlayfairDisplaySC-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/assets/fonts/PlayfairDisplaySC-Bold.ttf -------------------------------------------------------------------------------- /movie_hub/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /movie_hub/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/constants/constants.dart: -------------------------------------------------------------------------------- 1 | export 'asset.dart'; 2 | export 'error_text.dart'; 3 | export 'font_size.dart'; 4 | export 'palette.dart'; 5 | -------------------------------------------------------------------------------- /movie_hub/assets/fonts/PlayfairDisplaySC-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/assets/fonts/PlayfairDisplaySC-BoldItalic.ttf -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/nav_bar/nav_bar.dart: -------------------------------------------------------------------------------- 1 | export 'presentation/nav_bar_view.dart'; 2 | export 'change_notifier/nav_bar_notifier.dart'; 3 | export 'nav_bar_locator.dart'; -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/mipmap-hdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/android/app/src/main/res/mipmap-hdpi/launcher_icon.png -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/mipmap-mdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/android/app/src/main/res/mipmap-mdpi/launcher_icon.png -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /movie_hub/lib/cores/errors/error_text.dart: -------------------------------------------------------------------------------- 1 | class ErrorText { 2 | static const noInternet = 3 | "Poor Internet Connection, Please Check Your Internet and try again"; 4 | } 5 | -------------------------------------------------------------------------------- /movie_hub/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /movie_hub/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fiki2002/MovieHub/HEAD/movie_hub/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/kotlin/com/example/movie_hub/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.movie_hub 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /movie_hub/linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /movie_hub/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/cores.dart: -------------------------------------------------------------------------------- 1 | export 'shared/shared.dart'; 2 | export 'constants/constants.dart'; 3 | export 'errors/errors.dart'; 4 | export 'navigator/navigator.dart'; 5 | export 'utils/utils.dart'; 6 | export 'usecase/usecase.dart'; 7 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/data/model/search_params_model.dart: -------------------------------------------------------------------------------- 1 | class SearchParamsModel { 2 | final String query; 3 | final int page; 4 | SearchParamsModel({ 5 | required this.query, 6 | required this.page, 7 | }); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /movie_hub/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 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/arrow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_dashboard.dart: -------------------------------------------------------------------------------- 1 | export 'nav_bar/nav_bar.dart'; 2 | export 'home/home.dart'; 3 | export 'shared_widgets/widgets.dart'; 4 | export 'movie_details/movie_details.dart'; 5 | export 'watch_movies/watch_movies.dart'; 6 | export 'discover/search_movies.dart'; 7 | -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/data/model/auth_result_model.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:movie_hub/features/auth/auth.dart'; 3 | 4 | class AuthResultModel extends AuthResultEntity { 5 | const AuthResultModel({ 6 | required super.success, 7 | required super.message, 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/data/model/base_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:movie_hub/features/profile/profile.dart'; 2 | 3 | class BaseModel extends BaseEntity { 4 | const BaseModel({ 5 | required super.success, 6 | required super.message, 7 | super.data, 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /movie_hub/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/nav_bar/nav_bar_locator.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/nav_bar/nav_bar.dart'; 4 | 5 | 6 | void setUpNavBarLocator() { 7 | 8 | getIt.registerLazySingleton(() => NavBarNotifier()); 9 | } 10 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/utils/logger.dart: -------------------------------------------------------------------------------- 1 | import 'dart:developer' as dev; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | 5 | class AppLogger { 6 | AppLogger._(); 7 | 8 | static void log(Object? e, [s]) { 9 | if (kDebugMode == false) return; 10 | dev.log("$e StackTrace:: $s"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /movie_hub/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /movie_hub/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /movie_hub/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:326866166159:ios:e00e1669a233fe3db26bfa", 5 | "FIREBASE_PROJECT_ID": "moviehub-88129", 6 | "GCM_SENDER_ID": "326866166159" 7 | } -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/data/model/sign_up_params_model.dart: -------------------------------------------------------------------------------- 1 | class SignUpParamsModel { 2 | final String userName; 3 | final String password; 4 | final String email; 5 | 6 | SignUpParamsModel({ 7 | required this.userName, 8 | required this.password, 9 | required this.email, 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/eye.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /movie_hub/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /movie_hub/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /movie_hub/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /movie_hub/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /movie_hub/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /movie_hub/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /movie_hub/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 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/constants/palette.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | const Color kcWhiteColor = Color(0xffffffff); 4 | const Color kcPrimaryColor = Color(0xff13131A); 5 | const Color kcSuccessColor = Color(0xff15DC71); 6 | const Color kcErrorColor = Color(0xffFF0202); 7 | const Color kcBackground = Color(0xff1C1C27); 8 | const Color kcGrey = Colors.grey; 9 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/utils/utils.dart: -------------------------------------------------------------------------------- 1 | export 'extension.dart'; 2 | export 'http_helpers.dart'; 3 | export 'logger.dart'; 4 | export 'sizer.dart'; 5 | export 'type_defs.dart'; 6 | export 'setup.dart'; 7 | export 'api_keys.dart'; 8 | export 'exception/exception.dart'; 9 | export 'firebase_helper.dart'; 10 | export 'snack_bar_service.dart'; 11 | export 'precache_images.dart'; 12 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /movie_hub/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/errors/failures.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | abstract class Failure extends Equatable { 4 | const Failure({ 5 | this.message = "Something Went Wrong, Please Try Again", 6 | this.trace, 7 | }); 8 | 9 | final String message; 10 | final StackTrace? trace; 11 | 12 | @override 13 | List get props => [message, trace]; 14 | } 15 | -------------------------------------------------------------------------------- /movie_hub/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. -------------------------------------------------------------------------------- /movie_hub/linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /movie_hub/windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/home.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/domain/repository/search_movies_repository.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | 5 | abstract class SearchMoviesRepository { 6 | FutureOr> discoverMovies(int page); 7 | FutureOr> searchMovies(SearchParamsModel params); 8 | } 9 | -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/domain/entity/user_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class UserEntity extends Equatable { 4 | final String? email; 5 | final String? userName; 6 | final String? userId; 7 | 8 | const UserEntity({ 9 | this.email, 10 | this.userName, 11 | this.userId, 12 | }); 13 | 14 | @override 15 | List get props => [email, userName, userId]; 16 | } 17 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/shared/shared.dart: -------------------------------------------------------------------------------- 1 | export 'buttons.dart'; 2 | export 'app_bar_widget.dart'; 3 | export 'error_widget.dart'; 4 | export 'image_widget.dart'; 5 | export 'loading_widget.dart'; 6 | export 'retry_button_widget.dart'; 7 | export 'scaffold_widget.dart'; 8 | export 'success_view.dart'; 9 | export 'text_widget.dart'; 10 | export 'textfield_widget.dart'; 11 | export 'app_providers.dart'; 12 | export 'cached_network_image_widget.dart'; -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/domain/entity/base_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class BaseEntity extends Equatable { 4 | final bool success; 5 | final String message; 6 | final dynamic data; 7 | const BaseEntity({ 8 | required this.success, 9 | required this.message, 10 | required this.data, 11 | }); 12 | @override 13 | List get props => [success, message, data]; 14 | } 15 | -------------------------------------------------------------------------------- /movie_hub/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/utils/exception/base_exception.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:movie_hub/cores/cores.dart'; 3 | 4 | class BaseFailures extends Failure { 5 | const BaseFailures({required String message, StackTrace? trace}) 6 | : super(message: message, trace: trace); 7 | } 8 | 9 | class SocketFailures extends Failure { 10 | const SocketFailures({required String message, StackTrace? trace}) 11 | : super(message: message, trace: trace); 12 | } 13 | -------------------------------------------------------------------------------- /movie_hub/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /movie_hub/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /movie_hub/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 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/presentation/atoms/movie_not_found.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lottie/lottie.dart'; 3 | import 'package:movie_hub/cores/cores.dart'; 4 | 5 | class MovieNotFound extends StatelessWidget { 6 | const MovieNotFound({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Column( 11 | children: [ 12 | Lottie.asset(notFoundLottie), 13 | ], 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/domain/repository/profile_repo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:fpdart/fpdart.dart'; 4 | import 'package:movie_hub/cores/cores.dart'; 5 | import 'package:movie_hub/features/profile/profile.dart'; 6 | 7 | abstract class ProfileRepo { 8 | Future> fetchProfileDetails(); 9 | Future>> fetchAvatars(); 10 | Future> updateAvatar(String avatarUrl); 11 | } 12 | -------------------------------------------------------------------------------- /movie_hub/linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /movie_hub/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/domain/entity/user_details_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class UserDetailsEntity extends Equatable { 4 | final String? userName; 5 | final String? avatarUrl; 6 | final String? userId; 7 | final String? email; 8 | const UserDetailsEntity({ 9 | this.userName, 10 | this.avatarUrl, 11 | this.userId, 12 | this.email, 13 | }); 14 | @override 15 | List get props => [userId, userName, avatarUrl, email]; 16 | } 17 | -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/domain/entity/auth_result_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:movie_hub/features/auth/auth.dart'; 3 | 4 | class AuthResultEntity extends Equatable { 5 | final bool success; 6 | final String message; 7 | final UserEntity? user; 8 | 9 | const AuthResultEntity({ 10 | required this.success, 11 | required this.message, 12 | this.user, 13 | }); 14 | 15 | @override 16 | List get props => throw UnimplementedError(); 17 | } 18 | -------------------------------------------------------------------------------- /movie_hub/windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /movie_hub/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 | -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/watchlist/domain/repo/watch_list_repo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 5 | import 'package:movie_hub/features/profile/profile.dart'; 6 | 7 | abstract class WatchListRepo { 8 | Future> addToWatchList(String movieId); 9 | Future> removeFromWatchList(String movieId); 10 | FutureOr>> watchListMovieIds(); 11 | } 12 | -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /movie_hub/linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | 11 | void fl_register_plugins(FlPluginRegistry* registry) { 12 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = 13 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); 14 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); 15 | } 16 | -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/watch_list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/eye_close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/domain/usecases/get_popular_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 5 | 6 | class PopularMoviesUsecase implements UseCaseFuture { 7 | final HomeRepository homeRepository; 8 | PopularMoviesUsecase({ 9 | required this.homeRepository, 10 | }); 11 | 12 | @override 13 | FutureOr> call(int params) async { 14 | return await homeRepository.getPopularMovies(params); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/domain/repository/home_repository.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | 5 | abstract class HomeRepository { 6 | FutureOr> getTrendingMovies( 7 | String timeWindow, 8 | int page, 9 | ); 10 | 11 | FutureOr> getPopularMovies(int page); 12 | 13 | FutureOr> getTopRatedMovies(int page); 14 | 15 | FutureOr> getUpcomingMovies(int page); 16 | } 17 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/domain/usecases/get_top_rated_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | 5 | class TopRatedMoviesUseCase 6 | implements UseCaseFuture { 7 | final HomeRepository homeRepository; 8 | 9 | TopRatedMoviesUseCase({ 10 | required this.homeRepository, 11 | }); 12 | 13 | @override 14 | FutureOr> call(int params) async { 15 | return await homeRepository.getTopRatedMovies(params); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/navigator/error_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/shared/text_widget.dart'; 3 | import 'package:movie_hub/cores/constants/palette.dart'; 4 | 5 | Route errorRoute() { 6 | return MaterialPageRoute( 7 | builder: (_) { 8 | return Scaffold( 9 | appBar: AppBar( 10 | backgroundColor: kcBackground, 11 | title: const TextWidget('Page Not Found'), 12 | ), 13 | body: const Center( 14 | child: TextWidget('ERROR! Page not found'), 15 | ), 16 | ); 17 | }, 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/domain/usecases/get_upcoming_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | 5 | class GetUpcomingMoviesUseCase implements UseCaseFuture { 6 | final HomeRepository homeRepository; 7 | 8 | GetUpcomingMoviesUseCase({ 9 | required this.homeRepository, 10 | }); 11 | 12 | @override 13 | FutureOr> call(int params) async{ 14 | return await homeRepository.getUpcomingMovies(params); 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/domain/usecase/update_avatar_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:fpdart/fpdart.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/profile/profile.dart'; 4 | 5 | class UpdateAvatarUsecase 6 | implements UseCaseFuture { 7 | final ProfileRepo _profileRepo; 8 | 9 | UpdateAvatarUsecase({required ProfileRepo profileRepo}) 10 | : _profileRepo = profileRepo; 11 | 12 | @override 13 | Future> call(String params) async { 14 | return await _profileRepo.updateAvatar(params); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /movie_hub/README.md: -------------------------------------------------------------------------------- 1 | # movie_hub 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) 13 | 14 | For help getting started with Flutter development, view the 15 | [online documentation](https://docs.flutter.dev/), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/domain/usecase/get_similar_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 5 | 6 | class SimilarMovieUsecase implements UseCaseFuture { 7 | final MovieDetailRepository movieDetailRepo; 8 | SimilarMovieUsecase({ 9 | required this.movieDetailRepo, 10 | }); 11 | 12 | @override 13 | FutureOr> call(String params) async { 14 | return await movieDetailRepo.getSimilarMovies(params); 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/data/model/user_details_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:movie_hub/cores/cores.dart'; 2 | import 'package:movie_hub/features/profile/profile.dart'; 3 | 4 | class UserDetailsModel extends UserDetailsEntity { 5 | const UserDetailsModel({ 6 | super.userName, 7 | super.avatarUrl, 8 | super.userId, 9 | super.email, 10 | }); 11 | 12 | factory UserDetailsModel.fromMap(Mapped json) { 13 | return UserDetailsModel( 14 | userName: json['user_name'], 15 | avatarUrl: json['avatar_url'], 16 | userId: json['user_id'], 17 | email: json['email'], 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/data/models/see_all_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 3 | 4 | class SeeAllParams { 5 | final List movies; 6 | final String genreTitle; 7 | final bool Function(Notification)? onNotification; 8 | 9 | SeeAllParams({ 10 | required this.movies, 11 | required this.genreTitle, 12 | this.onNotification, 13 | }); 14 | 15 | void handleNotification(Notification notification) { 16 | if (onNotification != null) { 17 | onNotification!(notification); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/domain/usecase/get_movie_detail_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 5 | 6 | class MovieDetailUsecase 7 | implements UseCaseFuture { 8 | final MovieDetailRepository movieDetailRepo; 9 | MovieDetailUsecase({ 10 | required this.movieDetailRepo, 11 | }); 12 | 13 | @override 14 | FutureOr> call(String params) async { 15 | return await movieDetailRepo.getMovieDetails(params); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/domain/usecase/search_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 5 | 6 | class SearchMoviesUsecase 7 | implements UseCaseFuture { 8 | final SearchMoviesRepository searchMoviesRepo; 9 | SearchMoviesUsecase({ 10 | required this.searchMoviesRepo, 11 | }); 12 | 13 | @override 14 | FutureOr> call(SearchParamsModel params) async { 15 | return await searchMoviesRepo.searchMovies(params); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/utils/setup.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_core/firebase_core.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/services.dart'; 4 | import 'package:movie_hub/firebase_options.dart'; 5 | 6 | class Setups { 7 | static Future run() async { 8 | WidgetsFlutterBinding.ensureInitialized(); 9 | 10 | await Firebase.initializeApp( 11 | options: DefaultFirebaseOptions.currentPlatform, 12 | ); 13 | 14 | SystemChrome.setPreferredOrientations( 15 | [ 16 | DeviceOrientation.portraitUp, 17 | DeviceOrientation.portraitDown, 18 | ], 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/domain/usecase/discover_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | export 'package:fpdart/fpdart.dart'; 5 | 6 | class DiscoverMoviesUsecase implements UseCaseFuture { 7 | final SearchMoviesRepository searchMoviesRepo; 8 | DiscoverMoviesUsecase({ 9 | required this.searchMoviesRepo, 10 | }); 11 | 12 | @override 13 | FutureOr> call(int params) async{ 14 | return await searchMoviesRepo.discoverMovies(params); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/constants/error_text.dart: -------------------------------------------------------------------------------- 1 | const String noInternetConnectionText = 'Internet not connection found! \n ' 2 | 'Please check your internet connection and try again.'; 3 | 4 | void checkForError(Map data) { 5 | if (data['status'] == false || data['status'] == 'false') { 6 | final String? message = data['message'] ?? data['msg']; 7 | 8 | if (message == null) { 9 | final Map errorMap = Map.from(data['error']); 10 | 11 | throw errorMap.values.join('\n'); 12 | } else { 13 | throw message; 14 | } 15 | } 16 | 17 | if (data['data'] == null) { 18 | throw 'No data Found!'; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/domain/usecases/log_out_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:fpdart/fpdart.dart'; 4 | import 'package:movie_hub/cores/cores.dart'; 5 | import 'package:movie_hub/features/auth/auth.dart'; 6 | 7 | class LogOutUsecase implements UseCaseVoid { 8 | final AuthRepository _authenticationRepository; 9 | 10 | const LogOutUsecase({required AuthRepository authenticationRepository}) 11 | : _authenticationRepository = authenticationRepository; 12 | 13 | @override 14 | FutureOr> call(NoParams params) async { 15 | return await _authenticationRepository.logout(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/domain/usecase/fetch_avatars.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 5 | import 'package:movie_hub/features/profile/profile.dart'; 6 | 7 | class FetchAvatarsUsecase 8 | implements UseCaseFuture, NoParams> { 9 | final ProfileRepo _profileRepo; 10 | 11 | FetchAvatarsUsecase({ 12 | required profileRepo, 13 | }) : _profileRepo = profileRepo; 14 | 15 | @override 16 | FutureOr>> call(NoParams params) async { 17 | return await _profileRepo.fetchAvatars(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/domain/repository/auth_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:fpdart/fpdart.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/auth/auth.dart'; 4 | 5 | abstract class AuthRepository { 6 | Future> login({ 7 | required String email, 8 | required String password, 9 | }); 10 | 11 | Future> register( 12 | SignUpParamsModel signUpParams, 13 | ); 14 | 15 | Future> logout(); 16 | 17 | Future> forgotPassword(String email); 18 | 19 | Future> isUserLoggedIn(); 20 | } 21 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/domain/usecase/get_images_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/movies/discover/search_movies.dart'; 5 | import 'package:movie_hub/features/movies/movie_details/movie_details.dart'; 6 | 7 | class ImagesUsecase implements UseCaseFuture { 8 | final MovieDetailRepository movieDetailRepo; 9 | ImagesUsecase({ 10 | required this.movieDetailRepo, 11 | }); 12 | 13 | @override 14 | FutureOr> call(String params) async { 15 | return await movieDetailRepo.getImages(params); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/watchlist/domain/usecase/get_watchlist_movie_id_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:fpdart/fpdart.dart'; 4 | import 'package:movie_hub/cores/cores.dart'; 5 | import 'package:movie_hub/features/movies/watchlist/watchlist.dart'; 6 | 7 | class GetWatchListMovieIdsUsecase 8 | implements UseCaseFuture, NoParams> { 9 | final WatchListRepo watchListRepo; 10 | GetWatchListMovieIdsUsecase({ 11 | required this.watchListRepo, 12 | }); 13 | 14 | @override 15 | FutureOr>> call(NoParams params) async { 16 | return await watchListRepo.watchListMovieIds(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/shared/loading_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | 4 | class LoadingWidget extends StatelessWidget { 5 | const LoadingWidget({ 6 | Key? key, 7 | this.color, 8 | this.backGroundColor, 9 | this.radius, 10 | }) : super(key: key); 11 | 12 | final Color? color; 13 | final Color? backGroundColor; 14 | final double? radius; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Center( 19 | child: CupertinoActivityIndicator( 20 | color: color ?? kcWhiteColor, 21 | radius: radius ?? sr(10), 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/domain/repo/movie_detail_repo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:fpdart/fpdart.dart'; 4 | import 'package:movie_hub/cores/cores.dart'; 5 | import 'package:movie_hub/features/movies/home/home.dart'; 6 | import 'package:movie_hub/features/movies/movie_details/movie_details.dart'; 7 | 8 | abstract class MovieDetailRepository { 9 | FutureOr> getMovieDetails(String movieId); 10 | FutureOr> getImages(String movieId); 11 | FutureOr> getSimilarMovies(String movieId); 12 | Future> isMovieAWatchList(String movieId); 13 | } 14 | -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/domain/usecases/check_log_in_status_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:fpdart/fpdart.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/auth/auth.dart'; 4 | 5 | class CheckUserLoginStatusUsecase 6 | implements UseCaseFuture { 7 | final AuthRepository _authenticationRepository; 8 | 9 | CheckUserLoginStatusUsecase({required AuthRepository authenticationRepository}) 10 | : _authenticationRepository = authenticationRepository; 11 | 12 | @override 13 | Future> call(NoParams params) async { 14 | return await _authenticationRepository.isUserLoggedIn(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = movie_hub 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.movieHub 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. 15 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/sign_out.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/domain/usecase/is_movie_a_watchlist_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:fpdart/fpdart.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_details/movie_details.dart'; 4 | 5 | class CheckIfMovieIsAUsecase 6 | implements UseCaseFuture { 7 | final MovieDetailRepository _movieDetailRepo; 8 | 9 | CheckIfMovieIsAUsecase({ 10 | required MovieDetailRepository movieDetailRepo, 11 | }) : _movieDetailRepo = movieDetailRepo; 12 | 13 | @override 14 | Future> call(String params) async { 15 | return await _movieDetailRepo.isMovieAWatchList(params); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/presentation/atoms/watch_movie_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | 5 | class WatchMoviesButton extends StatelessWidget { 6 | const WatchMoviesButton({super.key, required this.movies}); 7 | final MovieDetailsParams movies; 8 | @override 9 | Widget build(BuildContext context) { 10 | return Button( 11 | text: 'Watch', 12 | circular: true, 13 | onTap: () => goTo( 14 | WatchMoviesView.route, 15 | arguments: movies.movieResults?.id.toString() ?? '', 16 | ), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/domain/usecases/forgot_password_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:fpdart/fpdart.dart'; 4 | import 'package:movie_hub/cores/cores.dart'; 5 | import 'package:movie_hub/features/auth/auth.dart'; 6 | 7 | class ForgotPasswordUsecase implements UseCaseVoid { 8 | final AuthRepository _authenticationRepository; 9 | 10 | const ForgotPasswordUsecase( 11 | {required AuthRepository authenticationRepository}) 12 | : _authenticationRepository = authenticationRepository; 13 | 14 | @override 15 | FutureOr> call(String params) async { 16 | return await _authenticationRepository.forgotPassword(params); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/domain/usecase/fetch_profile_details_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 5 | import 'package:movie_hub/features/profile/profile.dart'; 6 | 7 | class FetchProfileDetailsUsecase 8 | implements UseCaseFuture { 9 | final ProfileRepo _profileRepo; 10 | 11 | FetchProfileDetailsUsecase({ 12 | required profileRepo, 13 | }) : _profileRepo = profileRepo; 14 | 15 | @override 16 | FutureOr> call(NoParams params) async { 17 | return await _profileRepo.fetchProfileDetails(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/watchlist/domain/usecase/add_to_watchlist_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:fpdart/fpdart.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/watchlist/watchlist.dart'; 4 | import 'package:movie_hub/features/profile/profile.dart'; 5 | 6 | class AddToWatchListUsecase 7 | implements UseCaseFuture { 8 | final WatchListRepo _watchListRepo; 9 | 10 | AddToWatchListUsecase({ 11 | required WatchListRepo watchListRepo, 12 | }) : _watchListRepo = watchListRepo; 13 | 14 | @override 15 | Future> call(String movieId) async { 16 | return await _watchListRepo.addToWatchList(movieId); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /movie_hub/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 | -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/domain/usecases/sign_up_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:fpdart/fpdart.dart'; 4 | import 'package:movie_hub/cores/cores.dart'; 5 | import 'package:movie_hub/features/auth/auth.dart'; 6 | 7 | class SignUpUsecase 8 | implements UseCaseFuture { 9 | final AuthRepository _authenticationRepository; 10 | 11 | const SignUpUsecase({required AuthRepository authenticationRepository}) 12 | : _authenticationRepository = authenticationRepository; 13 | 14 | @override 15 | FutureOr> call( 16 | SignUpParamsModel params, 17 | ) async { 18 | return await _authenticationRepository.register(params); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/watchlist/domain/usecase/remove_from_watch_list_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:fpdart/fpdart.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/watchlist/watchlist.dart'; 4 | import 'package:movie_hub/features/profile/profile.dart'; 5 | 6 | class RemoveFromWatchListUsecase 7 | implements UseCaseFuture { 8 | final WatchListRepo _watchListRepo; 9 | 10 | RemoveFromWatchListUsecase({ 11 | required WatchListRepo watchListRepo, 12 | }) : _watchListRepo = watchListRepo; 13 | 14 | @override 15 | Future> call(String movieId) async { 16 | return await _watchListRepo.removeFromWatchList(movieId); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/watchlist/watchlist.dart: -------------------------------------------------------------------------------- 1 | export 'presentation/views/watchlist_view.dart'; 2 | export 'domain/repo/watch_list_repo.dart'; 3 | export 'domain/usecase/add_to_Watchlist_usecase.dart'; 4 | export 'presentation/notifier/add_to_watch_list_notifier.dart'; 5 | export 'watchlist_locator.dart'; 6 | export 'presentation/notifier/get_watch_list_movie_id_notifier.dart'; 7 | export 'data/datasource/watch_list_data_source.dart'; 8 | export 'data/repo-impl/watch_list_repo_impl.dart'; 9 | export 'domain/usecase/get_watchlist_movie_id_usecase.dart'; 10 | export 'presentation/widgets/watch_list_body_widget.dart'; 11 | export 'domain/usecase/remove_from_watch_list_usecase.dart'; 12 | export 'presentation/notifier/remove_movie_from_watchlist.dart'; 13 | -------------------------------------------------------------------------------- /movie_hub/windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/constants/font_size.dart: -------------------------------------------------------------------------------- 1 | const double kSize5 = 5.0; 2 | 3 | /// very tiny text font size 4 | const double kfsVeryTiny = 12.0; 5 | 6 | const double kMinute = 10.0; 7 | 8 | /// tiny text font size 9 | const double kfsTiny = 14.0; 10 | 11 | /// medium text font size 12 | const double kfsMedium = 16.0; 13 | 14 | /// large text font size 15 | const double kfsLarge = 18.0; 16 | 17 | /// extra large text font size 18 | const double kfsExtraLarge = 20.0; 19 | 20 | /// super large(H1) text font size 21 | const double kfsSuperLarge = 22.0; 22 | 23 | const double kGlobalPadding = 24.0; 24 | 25 | const double kXtremeLarge = 40.0; 26 | 27 | const double kfs70 = 70.0; 28 | 29 | const double kfs30 = 30.0; 30 | 31 | const double kfs90 = 90.0; 32 | 33 | const double kfs50 = 50.0; 34 | -------------------------------------------------------------------------------- /movie_hub/android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "326866166159", 4 | "project_id": "moviehub-88129", 5 | "storage_bucket": "moviehub-88129.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:326866166159:android:f042fcdb0fdc10d7b26bfa", 11 | "android_client_info": { 12 | "package_name": "com.example.movie_hub" 13 | } 14 | }, 15 | "oauth_client": [], 16 | "api_key": [ 17 | { 18 | "current_key": "AIzaSyDP4e4KDUuU5MjF8MZ95SDroIKgUiAfL2c" 19 | } 20 | ], 21 | "services": { 22 | "appinvite_service": { 23 | "other_platform_oauth_client": [] 24 | } 25 | } 26 | } 27 | ], 28 | "configuration_version": "1" 29 | } -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/search_movies.dart: -------------------------------------------------------------------------------- 1 | export 'presentation/views/search_view.dart'; 2 | export 'data/datasource/remote_data_source.dart'; 3 | export 'data/repo_impl/search_movies_repository_impl.dart'; 4 | export 'domain/repository/search_movies_repository.dart'; 5 | export 'domain/usecase/discover_movies_usecase.dart'; 6 | export 'domain/usecase/search_movies_usecase.dart'; 7 | export 'presentation/components/header.dart'; 8 | export 'presentation/notifier/discover_movies_notifier.dart'; 9 | export 'presentation/components/discover_movies_grid.dart'; 10 | export 'search_locator.dart'; 11 | export 'data/model/search_params_model.dart'; 12 | export 'presentation/notifier/search_movies_notifier.dart'; 13 | export 'presentation/components/search_movies_grid.dart'; 14 | export 'presentation/atoms/movie_not_found.dart'; -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java: -------------------------------------------------------------------------------- 1 | // Generated file. 2 | // 3 | // If you wish to remove Flutter's multidex support, delete this entire file. 4 | // 5 | // Modifications to this file should be done in a copy under a different name 6 | // as this file may be regenerated. 7 | 8 | package io.flutter.app; 9 | 10 | import android.app.Application; 11 | import android.content.Context; 12 | import androidx.annotation.CallSuper; 13 | import androidx.multidex.MultiDex; 14 | 15 | /** 16 | * Extension of {@link android.app.Application}, adding multidex support. 17 | */ 18 | public class FlutterMultiDexApplication extends Application { 19 | @Override 20 | @CallSuper 21 | protected void attachBaseContext(Context base) { 22 | super.attachBaseContext(base); 23 | MultiDex.install(this); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/nav_bar/change_notifier/nav_bar_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 3 | import 'package:movie_hub/features/movies/watchlist/watchlist.dart'; 4 | import 'package:movie_hub/features/profile/profile.dart'; 5 | 6 | class NavBarNotifier extends ChangeNotifier { 7 | int _currentIndex = 0; 8 | int get currentIndex => _currentIndex; 9 | 10 | final List _screens = [ 11 | const HomeView(), 12 | const SearchView(), 13 | const WatchListView(), 14 | const ProfileView(), 15 | ]; 16 | List get screens => _screens; 17 | 18 | void onNavBarTapped(int index) { 19 | _currentIndex = index; 20 | notifyListeners(); 21 | } 22 | 23 | void reset() { 24 | _currentIndex = 0; 25 | notifyListeners(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/auth.dart: -------------------------------------------------------------------------------- 1 | export 'auth_locator.dart'; 2 | export 'data/datasource/auth_data_source.dart'; 3 | export 'data/model/auth_result_model.dart'; 4 | export 'data/model/sign_up_params_model.dart'; 5 | export 'data/repo_impl/auth_repo_impl.dart'; 6 | export 'domain/entity/auth_result_entity.dart'; 7 | export 'domain/entity/user_entity.dart'; 8 | export 'domain/repository/auth_repository.dart'; 9 | export 'domain/usecases/sign_up_usecase.dart'; 10 | export 'presentation/views/forgot_password_view.dart'; 11 | export 'presentation/views/sign_in_view.dart'; 12 | export 'presentation/views/sign_up_view.dart'; 13 | export 'domain/usecases/forgot_password_usecase.dart'; 14 | export 'domain/usecases/log_in_usecase.dart'; 15 | export 'domain/usecases/log_out_usecase.dart'; 16 | export 'presentation/notifier/auth_notifier.dart'; 17 | export 'domain/usecases/check_log_in_status_usecase.dart'; -------------------------------------------------------------------------------- /movie_hub/linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | url_launcher_linux 7 | ) 8 | 9 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 10 | ) 11 | 12 | set(PLUGIN_BUNDLED_LIBRARIES) 13 | 14 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 15 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 16 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 19 | endforeach(plugin) 20 | 21 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 23 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 24 | endforeach(ffi_plugin) 25 | -------------------------------------------------------------------------------- /movie_hub/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 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/domain/usecases/get_trending_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 5 | 6 | class TrendingMoviesUseCase 7 | implements UseCaseFuture { 8 | final HomeRepository homeRepository; 9 | 10 | TrendingMoviesUseCase({ 11 | required this.homeRepository, 12 | }); 13 | 14 | @override 15 | FutureOr> call( 16 | TrendingMoviesParams params, 17 | ) async { 18 | return await homeRepository.getTrendingMovies( 19 | params.timeWindow, 20 | params.page, 21 | ); 22 | } 23 | } 24 | 25 | class TrendingMoviesParams { 26 | final String timeWindow; 27 | final int page; 28 | TrendingMoviesParams({ 29 | required this.timeWindow, 30 | required this.page, 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/atoms/shimmer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:shimmer/shimmer.dart'; 4 | 5 | class ShimmerWidget extends StatelessWidget { 6 | const ShimmerWidget({ 7 | super.key, 8 | this.height, 9 | this.highlightColor, 10 | this.baseColor, 11 | }); 12 | final double? height; 13 | final Color? highlightColor; 14 | final Color? baseColor; 15 | @override 16 | Widget build(BuildContext context) { 17 | return Shimmer.fromColors( 18 | baseColor: baseColor ?? kcBackground, 19 | highlightColor: highlightColor ?? Colors.white, 20 | child: ColoredBox( 21 | color: Colors.black.withOpacity(.04), 22 | child: SizedBox( 23 | height: height ?? screenHeight * .5, 24 | width: double.infinity, 25 | ), 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/presentation/components/image_preview_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | 4 | class ImagePreview extends StatelessWidget { 5 | static const String route = '/image-preview'; 6 | 7 | const ImagePreview({ 8 | super.key, 9 | required this.imageUrl, 10 | }); 11 | final String imageUrl; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return ScaffoldWidget( 16 | appBar: AppBar( 17 | backgroundColor: kcBackground, 18 | elevation: 0, 19 | ), 20 | useSingleScroll: false, 21 | usePadding: false, 22 | body: InteractiveViewer( 23 | child: Center( 24 | child: ImageWidget( 25 | imageTypes: ImageTypes.network, 26 | imageUrl: imageUrl, 27 | ), 28 | ), 29 | ), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/profile.dart: -------------------------------------------------------------------------------- 1 | export 'presentation/views/profile_view.dart'; 2 | export 'domain/entity/user_details_entity.dart'; 3 | export 'data/model/user_details_model.dart'; 4 | export 'data/datasource/profile_datasource.dart'; 5 | export 'domain/repository/profile_repo.dart'; 6 | export 'data/repo-impl/profile_repo_impl.dart'; 7 | export 'profile_locator.dart'; 8 | export 'presentation/notifier/fetch_profile_details_notifier.dart'; 9 | export 'presentation/atoms/action_list_tile.dart'; 10 | export 'domain/usecase/fetch_profile_details_usecase.dart'; 11 | export 'domain/usecase/fetch_avatars.dart'; 12 | export 'presentation/components/avatar_screen.dart'; 13 | export 'presentation/notifier/fetch_avatars_notifier.dart'; 14 | export 'domain/entity/base_entity.dart'; 15 | export 'data/model/base_model.dart'; 16 | export 'domain/usecase/update_avatar_usecase.dart'; 17 | export 'presentation/notifier/update_avatar_notifier.dart'; 18 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/shared/retry_button_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/shared/text_widget.dart'; 3 | import 'package:movie_hub/cores/constants/palette.dart'; 4 | 5 | class RetryButtonWidget extends StatelessWidget { 6 | const RetryButtonWidget({Key? key, this.callback}) : super(key: key); 7 | 8 | final void Function()? callback; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return InkWell( 13 | onTap: () => callback!.call(), 14 | child: Container( 15 | padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 5.0), 16 | decoration: BoxDecoration( 17 | border: Border.all(color: kcWhiteColor), 18 | borderRadius: BorderRadius.circular(5.0), 19 | ), 20 | child: const TextWidget( 21 | 'Retry', 22 | fontWeight: FontWeight.w300, 23 | ), 24 | ), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/domain/usecases/log_in_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:fpdart/fpdart.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/auth/auth.dart'; 4 | 5 | class LoginUsecase 6 | implements UseCaseFuture { 7 | final AuthRepository _authenticationRepository; 8 | 9 | LoginUsecase({required AuthRepository authenticationRepository}) 10 | : _authenticationRepository = authenticationRepository; 11 | 12 | @override 13 | Future> call(LoginDataParams login) async { 14 | return await _authenticationRepository.login( 15 | email: login.email, 16 | password: login.password, 17 | ); 18 | } 19 | } 20 | 21 | class LoginDataParams { 22 | final String email; 23 | final String password; 24 | 25 | LoginDataParams({ 26 | required this.email, 27 | required this.password, 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/utils/precache_images.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:movie_hub/cores/cores.dart'; 4 | 5 | class PreCacheImage { 6 | static final BuildContext context = navigatorKey.currentContext!; 7 | 8 | static Future loadImages({ 9 | required String backDrop, 10 | String? posterPath, 11 | }) async { 12 | try { 13 | if (backDrop.isEmpty || (posterPath == null || posterPath.isEmpty)) { 14 | return; 15 | } 16 | 17 | await Future.wait([ 18 | _precache(backDrop), 19 | _precache(posterPath), 20 | ]); 21 | } catch (e) { 22 | e.log(); 23 | 'Failed to cache image!!'.log(); 24 | } 25 | } 26 | 27 | static Future _precache(String path) async { 28 | await precacheImage( 29 | CachedNetworkImageProvider('$baseNetworkImage$path'), 30 | context, 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /movie_hub/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.2.0' 10 | // START: FlutterFire Configuration 11 | classpath 'com.google.gms:google-services:4.3.10' 12 | classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' 13 | // END: FlutterFire Configuration 14 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | mavenCentral() 22 | } 23 | } 24 | 25 | rootProject.buildDir = '../build' 26 | subprojects { 27 | project.buildDir = "${rootProject.buildDir}/${project.name}" 28 | } 29 | subprojects { 30 | project.evaluationDependsOn(':app') 31 | } 32 | 33 | tasks.register("clean", Delete) { 34 | delete rootProject.buildDir 35 | } 36 | -------------------------------------------------------------------------------- /movie_hub/windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /movie_hub/windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | cloud_firestore 7 | firebase_auth 8 | firebase_core 9 | firebase_storage 10 | url_launcher_windows 11 | ) 12 | 13 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 14 | ) 15 | 16 | set(PLUGIN_BUNDLED_LIBRARIES) 17 | 18 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 19 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 20 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 21 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 23 | endforeach(plugin) 24 | 25 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 26 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 27 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 28 | endforeach(ffi_plugin) 29 | -------------------------------------------------------------------------------- /movie_hub/ios/Runner/GoogleService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | API_KEY 6 | AIzaSyAMS8FcznT38I1eKL7LJ9gPxmRKtDERJVI 7 | GCM_SENDER_ID 8 | 326866166159 9 | PLIST_VERSION 10 | 1 11 | BUNDLE_ID 12 | com.example.movieHub 13 | PROJECT_ID 14 | moviehub-88129 15 | STORAGE_BUCKET 16 | moviehub-88129.appspot.com 17 | IS_ADS_ENABLED 18 | 19 | IS_ANALYTICS_ENABLED 20 | 21 | IS_APPINVITE_ENABLED 22 | 23 | IS_GCM_ENABLED 24 | 25 | IS_SIGNIN_ENABLED 26 | 27 | GOOGLE_APP_ID 28 | 1:326866166159:ios:e00e1669a233fe3db26bfa 29 | 30 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/utils/firebase_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:firebase_auth/firebase_auth.dart'; 3 | import 'package:movie_hub/cores/cores.dart'; 4 | 5 | String userCollection = "users"; 6 | 7 | class FirebaseHelper { 8 | final fireStore = FirebaseFirestore.instance; 9 | 10 | /// -------- AUTHENTICATION --------- /// 11 | FirebaseAuth get auth => FirebaseAuth.instance; 12 | String? get currentUserId { 13 | final String? userId = auth.currentUser?.uid; 14 | if (userId == null) throw const BaseFailures(message: 'User not found!'); 15 | 16 | return userId; 17 | } 18 | 19 | /// ------ FIRESTORE ------ /// 20 | CollectionReference> userCollectionRef() { 21 | return FirebaseFirestore.instance.collection(userCollection); 22 | } 23 | 24 | CollectionReference> watchListRef({ 25 | required String userId, 26 | }) { 27 | return userCollectionRef().doc(userId).collection('watch_list'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/navigator/app_router.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | final GlobalKey navigatorKey = GlobalKey(); 4 | 5 | Future goTo(String routeName, {Object? arguments}) { 6 | return navigatorKey.currentState!.pushNamed( 7 | routeName, 8 | arguments: arguments, 9 | ); 10 | } 11 | 12 | Future go(Widget page) { 13 | return navigatorKey.currentState!.push( 14 | MaterialPageRoute(builder: (context) => page), 15 | ); 16 | } 17 | 18 | Future goReplace(String routeName) { 19 | return navigatorKey.currentState!.pushReplacementNamed(routeName); 20 | } 21 | 22 | Future clearRoad(String routeName) { 23 | return navigatorKey.currentState!.pushNamedAndRemoveUntil( 24 | routeName, 25 | 26 | ///similar to (Route route)=> route.settings.name == '/' 27 | ///where '/' is the last page. 28 | ModalRoute.withName('/'), 29 | ); 30 | } 31 | 32 | void goBack([Object? result]) { 33 | return navigatorKey.currentState!.pop(result); 34 | } 35 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/utils/sizer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:movie_hub/cores/cores.dart'; 4 | 5 | /// return a percentage of the screen height in respect to the value given 6 | double sh(double value) => (value / 100).sh; 7 | 8 | /// return a percentage of the screen width in respect to the value given 9 | double sw(double value) => (value / 100).sw; 10 | 11 | /// Calculates the sp (Scalable Pixel) depending on the device's screen size 12 | double sp(double value) => value.sp; 13 | 14 | double h(double value) => value.h; 15 | 16 | double w(double value) => value.w; 17 | 18 | double sr(double value) => value.r; 19 | 20 | Widget vSpace(double value) => value.verticalSpace; 21 | 22 | Widget hSpace(double value) => value.horizontalSpace; 23 | 24 | double get screenWidth => 25 | MediaQuery.sizeOf(navigatorKey.currentState!.context).width; 26 | 27 | double get screenHeight => 28 | MediaQuery.sizeOf(navigatorKey.currentState!.context).height; 29 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/add_avatar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/watchlist/presentation/notifier/get_watch_list_movie_id_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/watchlist/watchlist.dart'; 4 | 5 | class GetWatchListMovieIdsNotifier extends ChangeNotifier { 6 | final GetWatchListMovieIdsUsecase _watchListMovieIdUsecase; 7 | 8 | GetWatchListMovieIdsNotifier({ 9 | required watchListMovieIdUsecase, 10 | }) : _watchListMovieIdUsecase = watchListMovieIdUsecase; 11 | 12 | Future init() async { 13 | await getWatchListMovieId(); 14 | } 15 | 16 | final List _allMovieIds = []; 17 | List get allMovieIds => _allMovieIds; 18 | 19 | Future getWatchListMovieId() async { 20 | final res = await _watchListMovieIdUsecase.call(const NoParams()); 21 | return res.fold( 22 | (l) {}, 23 | (r) async { 24 | _allMovieIds.addAll(r); 25 | }, 26 | ); 27 | } 28 | 29 | } 30 | 31 | enum GetWatchListState { isDone, loading, error } 32 | -------------------------------------------------------------------------------- /movie_hub/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "movie_hub", 3 | "short_name": "movie_hub", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /movie_hub/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:ui'; 3 | 4 | import 'package:firebase_crashlytics/firebase_crashlytics.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:movie_hub/app/my_app.dart'; 7 | import 'package:movie_hub/app/locator.dart'; 8 | import 'package:movie_hub/cores/cores.dart'; 9 | 10 | void main() async { 11 | runZonedGuarded>( 12 | () async { 13 | WidgetsFlutterBinding.ensureInitialized(); 14 | SetUpLocators.init(); 15 | 16 | await Setups.run(); 17 | FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); 18 | 19 | FlutterError.onError = 20 | FirebaseCrashlytics.instance.recordFlutterFatalError; 21 | 22 | PlatformDispatcher.instance.onError = (error, stack) { 23 | FirebaseCrashlytics.instance.recordError(error, stack, fatal: true); 24 | return true; 25 | }; 26 | 27 | runApp(const MyApp()); 28 | }, 29 | (error, stackTrace) => FirebaseCrashlytics.instance 30 | .recordError(error, stackTrace, fatal: true), 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /movie_hub/windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/presentation/views/search_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | class SearchView extends StatelessWidget { 7 | const SearchView({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return ScaffoldWidget( 12 | useSingleScroll: false, 13 | usePadding: false, 14 | appBar: const SearchHeaderWidget( 15 | title: 'Discover', 16 | ), 17 | body: Padding( 18 | padding: const EdgeInsets.fromLTRB( 19 | kfsExtraLarge, 20 | kfsExtraLarge, 21 | kfsExtraLarge, 22 | 0, 23 | ), 24 | child: Consumer( 25 | builder: (context, search, _) { 26 | return search.isSearching 27 | ? const SearchMoviesGrid() 28 | : const DiscoverMoviesSection(); 29 | }, 30 | ), 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /movie_hub/lib/app/my_app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/splash/splash.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return ScreenUtilInit( 13 | designSize: const Size(360, 690), 14 | minTextAdapt: true, 15 | splitScreenMode: true, 16 | builder: (context, Widget? child) { 17 | return MultiProvider( 18 | providers: providers, 19 | child: MaterialApp( 20 | title: 'Movie Hub', 21 | debugShowCheckedModeBanner: false, 22 | initialRoute: SplashPage.route, 23 | theme: ThemeData( 24 | scaffoldBackgroundColor: kcBackground, 25 | ), 26 | onGenerateRoute: RouteGenerator.generateRoute, 27 | navigatorKey: navigatorKey, 28 | ), 29 | ); 30 | }, 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/presentation/atoms/grid_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | 5 | class GridViewWidget extends StatelessWidget { 6 | const GridViewWidget({super.key, required this.list}); 7 | final List list; 8 | @override 9 | Widget build(BuildContext context) { 10 | return GridView.builder( 11 | itemCount: list.length, 12 | shrinkWrap: true, 13 | padding: EdgeInsets.zero, 14 | physics: const NeverScrollableScrollPhysics(), 15 | itemBuilder: (context, int index) { 16 | return MovieCardTile( 17 | imageUrl: list[index].filePath ?? '', 18 | onTap: () => goTo( 19 | ImagePreview.route, 20 | arguments: list[index].filePath, 21 | ), 22 | ); 23 | }, 24 | gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( 25 | crossAxisCount: 3, 26 | mainAxisSpacing: kMinute, 27 | crossAxisSpacing: kMinute, 28 | ), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "movie_hub", 9 | "cwd": "movie_hub", 10 | "request": "launch", 11 | "type": "dart" 12 | }, 13 | { 14 | "name": "movie_hub (profile mode)", 15 | "cwd": "movie_hub", 16 | "request": "launch", 17 | "type": "dart", 18 | "flutterMode": "profile" 19 | }, 20 | { 21 | "name": "movie_hub (release mode)", 22 | "cwd": "movie_hub", 23 | "request": "launch", 24 | "type": "dart", 25 | "flutterMode": "release" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /movie_hub/lib/app/locator.dart: -------------------------------------------------------------------------------- 1 | import 'package:get_it/get_it.dart'; 2 | import 'package:movie_hub/features/auth/auth.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | import 'package:movie_hub/features/movies/watchlist/watchlist.dart'; 5 | import 'package:movie_hub/features/profile/profile.dart'; 6 | 7 | class SetUpLocators { 8 | static const SetUpLocators _instance = SetUpLocators._(); 9 | const SetUpLocators._(); 10 | 11 | factory SetUpLocators() => _instance; 12 | 13 | static final getIt = GetIt.instance; 14 | 15 | static void init() { 16 | //! ****** NavBar Locator ****** !// 17 | setUpNavBarLocator(); 18 | 19 | //! ***** Auth Locator ****** !// 20 | setUpAuthLocator(); 21 | 22 | //! ****** Home Locator ****** !// 23 | setUpHomeLocator(); 24 | 25 | //! ****** Movie Details Locator ****** !// 26 | setUpMovieLocator(); 27 | 28 | //! ****** Search Movies Locator ****** !// 29 | setUpSearchLocator(); 30 | 31 | //! ******* Profile ******** !// 32 | setUpProfileLocator(); 33 | 34 | //! ******* WatchList ******** !// 35 | setUpWatchListLocator(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /movie_hub/windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | void RegisterPlugins(flutter::PluginRegistry* registry) { 16 | CloudFirestorePluginCApiRegisterWithRegistrar( 17 | registry->GetRegistrarForPlugin("CloudFirestorePluginCApi")); 18 | FirebaseAuthPluginCApiRegisterWithRegistrar( 19 | registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi")); 20 | FirebaseCorePluginCApiRegisterWithRegistrar( 21 | registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); 22 | FirebaseStoragePluginCApiRegisterWithRegistrar( 23 | registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi")); 24 | UrlLauncherWindowsRegisterWithRegistrar( 25 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 26 | } 27 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/watch_movies/presentation/watch_movies_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_inappwebview/flutter_inappwebview.dart'; 3 | import 'package:movie_hub/cores/cores.dart'; 4 | 5 | class WatchMoviesView extends StatefulWidget { 6 | static const String route = '/watch-movies'; 7 | final String movieID; 8 | const WatchMoviesView({ 9 | super.key, 10 | required this.movieID, 11 | }); 12 | 13 | @override 14 | State createState() => _WatchMoviesViewState(); 15 | } 16 | 17 | class _WatchMoviesViewState extends State { 18 | late InAppWebViewController controller; 19 | @override 20 | Widget build(BuildContext context) { 21 | return Scaffold( 22 | body: InAppWebView( 23 | initialUrlRequest: URLRequest( 24 | url: Uri.parse( 25 | '$videoBaseUrl${widget.movieID}', 26 | ), 27 | ), 28 | onWebViewCreated: (InAppWebViewController inAppWebViewController) { 29 | controller = inAppWebViewController; 30 | controller.getOriginalUrl(); 31 | }, 32 | ), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/presentation/notifier/image_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/features/movies/movie_details/movie_details.dart'; 3 | 4 | class ImageNotifier extends ChangeNotifier { 5 | final ImagesUsecase imageUsecase; 6 | 7 | ImageNotifier({ 8 | required this.imageUsecase, 9 | }); 10 | 11 | 12 | ImageModel? _images; 13 | ImageModel? get images => _images; 14 | Future getImages(String movieId) async { 15 | _setImageState(ImageNotifierState.loading); 16 | final res = await imageUsecase.call(movieId); 17 | 18 | res.fold( 19 | (l) { 20 | _setImageState(ImageNotifierState.error); 21 | }, 22 | (r) { 23 | _images = r; 24 | notifyListeners(); 25 | _setImageState(ImageNotifierState.done); 26 | }, 27 | ); 28 | } 29 | 30 | ImageNotifierState _imageState = ImageNotifierState.done; 31 | ImageNotifierState get imageState => _imageState; 32 | 33 | void _setImageState(ImageNotifierState state) { 34 | _imageState = state; 35 | notifyListeners(); 36 | } 37 | } 38 | 39 | enum ImageNotifierState { loading, done, error } 40 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/home.dart: -------------------------------------------------------------------------------- 1 | export 'presentation/views/home_view.dart'; 2 | export 'domain/repository/home_repository.dart'; 3 | export 'domain/usecases/get_trending_movies_usecase.dart'; 4 | export 'data/datasource/home_remote_data_source.dart'; 5 | export 'presentation/atoms/trending_movies_preview.dart'; 6 | export 'presentation/notifier/trending_movies_notifier.dart'; 7 | export 'data/repository_impls/home_repository_impl.dart'; 8 | export 'home_locator.dart'; 9 | export 'data/models/movies_model.dart'; 10 | export 'domain/entities/movie_entity.dart'; 11 | export 'domain/usecases/get_popular_movies_usecase.dart'; 12 | export 'presentation/notifier/popular_movies_notifier.dart'; 13 | export 'presentation/atoms/shimmer.dart'; 14 | export 'presentation/notifier/top_rated_movies_notifier.dart'; 15 | export 'domain/usecases/get_top_rated_movies_usecase.dart'; 16 | export 'domain/usecases/get_upcoming_movies_usecase.dart'; 17 | export 'presentation/notifier/trending_for_the_week_notifier.dart'; 18 | export 'presentation/atoms/image_preview.dart'; 19 | export 'presentation/notifier/upcoming_movies_notifier.dart'; 20 | export 'presentation/components/see_all_movies.dart'; 21 | export 'data/models/see_all_params.dart'; -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/presentation/atoms/action_list_tile.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | 4 | class ActionListTile extends StatelessWidget { 5 | const ActionListTile({ 6 | Key? key, 7 | required this.title, 8 | required this.icon, 9 | required this.onTap, 10 | }) : super(key: key); 11 | final String title; 12 | final String icon; 13 | final VoidCallback onTap; 14 | @override 15 | Widget build(BuildContext context) { 16 | return GestureDetector( 17 | onTap: onTap, 18 | child: Container( 19 | padding: const EdgeInsets.all(kfsExtraLarge), 20 | decoration: BoxDecoration( 21 | borderRadius: BorderRadius.circular(kfsTiny), 22 | color: kcWhiteColor.withOpacity(.1), 23 | ), 24 | child: Row( 25 | children: [ 26 | ImageWidget( 27 | imageTypes: ImageTypes.svg, 28 | imageUrl: icon, 29 | color: kcWhiteColor, 30 | useIconColor: true, 31 | ), 32 | hSpace(kMinute), 33 | TextWidget(title), 34 | ], 35 | ), 36 | ), 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /movie_hub/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import cloud_firestore 9 | import firebase_auth 10 | import firebase_core 11 | import firebase_crashlytics 12 | import firebase_storage 13 | import path_provider_foundation 14 | import sqflite 15 | import url_launcher_macos 16 | 17 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 18 | FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) 19 | FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) 20 | FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) 21 | FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCrashlyticsPlugin")) 22 | FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin")) 23 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 24 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) 25 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 26 | } 27 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/presentation/notifier/fetch_avatars_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/profile/profile.dart'; 4 | 5 | class FetchAvatarNotifier extends ChangeNotifier { 6 | final FetchAvatarsUsecase _fetchAvatarsUsecase; 7 | 8 | FetchAvatarNotifier({ 9 | required fetchAvatarsUsecase, 10 | }) : _fetchAvatarsUsecase = fetchAvatarsUsecase; 11 | 12 | List? _avatarList; 13 | List? get listOfAvatar => _avatarList; 14 | 15 | Future fetchAvatar() async { 16 | _setAvatarState(FetchAvatarState.isLoading); 17 | final res = await _fetchAvatarsUsecase.call(const NoParams()); 18 | res.fold( 19 | (l) {}, 20 | (r) { 21 | _avatarList = r; 22 | notifyListeners(); 23 | _setAvatarState(FetchAvatarState.isDone); 24 | }, 25 | ); 26 | } 27 | 28 | FetchAvatarState _avatarState = FetchAvatarState.isDone; 29 | FetchAvatarState get avatarState => _avatarState; 30 | 31 | void _setAvatarState(FetchAvatarState state) { 32 | _avatarState = state; 33 | notifyListeners(); 34 | } 35 | } 36 | 37 | enum FetchAvatarState { isLoading, isError, isDone } 38 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/person.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/constants/asset.dart: -------------------------------------------------------------------------------- 1 | const _baseIcons = 'assets/icons'; 2 | const _baseLottie = 'assets/lottie'; 3 | const baseNetworkImage = 'https://image.tmdb.org/t/p/original'; 4 | 5 | const personIcon = '$_baseIcons/person.svg'; 6 | const mailIcon = '$_baseIcons/mail.svg'; 7 | const lockIcon = '$_baseIcons/lock.svg'; 8 | const eyeIcon = '$_baseIcons/eye.svg'; 9 | const eyeCloseIcon = '$_baseIcons/eye_close.svg'; 10 | const searchIcon = '$_baseIcons/search.svg'; 11 | const homeIcon = '$_baseIcons/home.svg'; 12 | const userIcon = '$_baseIcons/user.svg'; 13 | const listIcon = '$_baseIcons/watch_list.svg'; 14 | const arrowLeftIcon = '$_baseIcons/arrow.svg'; 15 | const profileImg = '$_baseIcons/profile.png'; 16 | const addAvatarIcon = '$_baseIcons/add_avatar.svg'; 17 | const signOutIcon = '$_baseIcons/sign_out.svg'; 18 | const addIcon = '$_baseIcons/add.svg'; 19 | const checkIcon = '$_baseIcons/check.svg'; 20 | 21 | const notFoundLottie = '$_baseLottie/not_found.json'; 22 | const loadingFailed = '$_baseLottie/loading_failed.json'; 23 | const emptyWatchList = '$_baseLottie/empty_watchlist.json'; 24 | 25 | const playFair = 'Playfair'; 26 | 27 | const String email = 'email'; 28 | const String password = 'password'; 29 | const String userName = 'userName'; 30 | -------------------------------------------------------------------------------- /movie_hub/.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 | **/lib/cores/utils/api_keys.dart 13 | 14 | # IntelliJ related 15 | *.iml 16 | *.ipr 17 | *.iws 18 | .idea/ 19 | 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | k 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .packages 33 | .pub-cache/ 34 | .pub/ 35 | /build/ 36 | 37 | # Web related 38 | lib/generated_plugin_registrant.dart 39 | 40 | # Symbolication related 41 | app.*.symbols 42 | 43 | # Obfuscation related 44 | app.*.map.json 45 | 46 | # Android Studio will place build artifacts here 47 | /android/app/debug 48 | /android/app/profile 49 | /android/app/release 50 | 51 | ios/build/ 52 | 53 | lib/generated/ 54 | lib/generated/intl 55 | lib/generated/intl/messages_all.dart 56 | lib/generated/intl/messages_en.dart 57 | lib/generated/l10n.dart 58 | 59 | #vscode related 60 | .vscode/ 61 | 62 | #fvm related 63 | .fvm/ -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/domain/entities/image_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class ImageEntity extends Equatable { 4 | final List? backdrops; 5 | final int? id; 6 | final List? logos; 7 | final List? posters; 8 | const ImageEntity({ 9 | this.backdrops, 10 | this.id, 11 | this.logos, 12 | this.posters, 13 | }); 14 | @override 15 | List get props => [ 16 | backdrops, 17 | id, 18 | logos, 19 | posters, 20 | ]; 21 | } 22 | 23 | class BackdropEntity extends Equatable { 24 | final double? aspectRatio; 25 | final int? height; 26 | final String? iso6391; 27 | final String? filePath; 28 | final double? voteAverage; 29 | final int? voteCount; 30 | final int? width; 31 | const BackdropEntity({ 32 | this.aspectRatio, 33 | this.height, 34 | this.iso6391, 35 | this.filePath, 36 | this.voteAverage, 37 | this.voteCount, 38 | this.width, 39 | }); 40 | 41 | @override 42 | List get props => [ 43 | aspectRatio, 44 | height, 45 | iso6391, 46 | filePath, 47 | voteAverage, 48 | voteCount, 49 | width, 50 | ]; 51 | } 52 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/data/datasource/remote_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:movie_hub/cores/cores.dart'; 2 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 3 | 4 | abstract class SearchMovieDataSource { 5 | Future discoverMovies(int page); 6 | Future searchMovies(SearchParamsModel params); 7 | } 8 | 9 | class SearchMovieDataSourceImpl extends SearchMovieDataSource { 10 | @override 11 | Future discoverMovies(int page) async { 12 | /// Fetches random movies that'd be under the Discover section 13 | final String url = '$baseUrl/discover/movie'; 14 | final result = await HttpHelper.get( 15 | url, 16 | query: { 17 | 'page': page, 18 | }, 19 | ); 20 | final MoviesModel discoverMovies = MoviesModel.fromJson(result); 21 | return discoverMovies; 22 | } 23 | 24 | @override 25 | Future searchMovies(SearchParamsModel params) async { 26 | //searches through movies 27 | final String url = '$baseUrl/search/movie'; 28 | final result = await HttpHelper.get( 29 | url, 30 | query: { 31 | 'query': params.query, 32 | 'page': params.page, 33 | }, 34 | ); 35 | final MoviesModel searchedMovies = MoviesModel.fromJson(result); 36 | return searchedMovies; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/presentation/notifier/fetch_profile_details_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/profile/profile.dart'; 4 | 5 | class FetchProfileNotifier extends ChangeNotifier { 6 | final FetchProfileDetailsUsecase _fetchProfileUsecase; 7 | 8 | FetchProfileNotifier({ 9 | required fetchProfileUsecase, 10 | }) : _fetchProfileUsecase = fetchProfileUsecase; 11 | 12 | UserDetailsModel? _userModel; 13 | UserDetailsModel? get userModel => _userModel; 14 | 15 | Future fetchProfileDetails() async { 16 | _setProfileState(FetchProfileState.isLoading); 17 | final res = await _fetchProfileUsecase.call(const NoParams()); 18 | res.fold( 19 | (l) { 20 | _setProfileState(FetchProfileState.isError); 21 | }, 22 | (r) { 23 | _userModel = r; 24 | notifyListeners(); 25 | _setProfileState(FetchProfileState.isDone); 26 | }, 27 | ); 28 | } 29 | 30 | FetchProfileState _profileState = FetchProfileState.isDone; 31 | FetchProfileState get profileState => _profileState; 32 | 33 | void _setProfileState(FetchProfileState state) { 34 | _profileState = state; 35 | notifyListeners(); 36 | } 37 | } 38 | 39 | enum FetchProfileState { isLoading, isError, isDone } 40 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/presentation/notifier/similar_movies_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/features/movies/home/home.dart'; 3 | import 'package:movie_hub/features/movies/movie_details/movie_details.dart'; 4 | 5 | class SimilarMoviesNotifier extends ChangeNotifier { 6 | final SimilarMovieUsecase similarMovieUsecase; 7 | 8 | SimilarMoviesNotifier({ 9 | required this.similarMovieUsecase, 10 | }); 11 | 12 | MoviesModel? _similarMovies; 13 | MoviesModel? get similarMovies => _similarMovies; 14 | 15 | Future getSimilarMovies(String movieId) async { 16 | _setSimilarState(SimilarMoviesState.isLoading); 17 | final res = await similarMovieUsecase.call(movieId); 18 | res.fold( 19 | (l) { 20 | _setSimilarState(SimilarMoviesState.isError); 21 | }, 22 | (r) { 23 | _similarMovies = r; 24 | notifyListeners(); 25 | _setSimilarState(SimilarMoviesState.isDone); 26 | }, 27 | ); 28 | } 29 | 30 | SimilarMoviesState _similarMoviesState = SimilarMoviesState.isDone; 31 | SimilarMoviesState get similarMoviesState => _similarMoviesState; 32 | 33 | void _setSimilarState(SimilarMoviesState state) { 34 | _similarMoviesState = state; 35 | notifyListeners(); 36 | } 37 | } 38 | 39 | enum SimilarMoviesState { isLoading, isError, isDone } 40 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/search_locator.dart: -------------------------------------------------------------------------------- 1 | import 'package:get_it/get_it.dart'; 2 | import 'package:movie_hub/app/app.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | 5 | void setUpSearchLocator() { 6 | final GetIt getIt = SetUpLocators.getIt; 7 | 8 | /// Data Source 9 | getIt.registerLazySingleton( 10 | () => SearchMovieDataSourceImpl(), 11 | ); 12 | 13 | /// Repository 14 | getIt.registerLazySingleton( 15 | () => SearchMovieImpl( 16 | searchMovieDataSource: getIt(), 17 | ), 18 | ); 19 | 20 | /// Usecase 21 | getIt.registerLazySingleton( 22 | () => DiscoverMoviesUsecase( 23 | searchMoviesRepo: getIt(), 24 | ), 25 | ); 26 | getIt.registerLazySingleton( 27 | () => SearchMoviesUsecase( 28 | searchMoviesRepo: getIt(), 29 | ), 30 | ); 31 | 32 | /// Notifier 33 | getIt.registerLazySingleton( 34 | () => DiscoverMoviesNotifier( 35 | discoverMoviesUsecase: getIt(), 36 | ), 37 | ); 38 | 39 | getIt.registerLazySingleton( 40 | () => SearchNotifier( 41 | searchMovieUsecase: getIt(), 42 | ), 43 | ); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/shared/error_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lottie/lottie.dart'; 3 | import 'package:movie_hub/cores/cores.dart'; 4 | 5 | class PageErrorWidget extends StatelessWidget { 6 | const PageErrorWidget({super.key, required this.onTap}); 7 | final VoidCallback onTap; 8 | @override 9 | Widget build(BuildContext context) { 10 | return SafeArea( 11 | child: Column( 12 | children: [ 13 | vSpace(screenHeight * .1), 14 | Lottie.asset(loadingFailed), 15 | AnimatedOpacity( 16 | opacity: 1, 17 | duration: const Duration(milliseconds: 400), 18 | child: Column( 19 | children: [ 20 | const Center( 21 | child: TextWidget( 22 | 'Something went wrong!😓\nYou should check your internet connection', 23 | textAlign: TextAlign.center, 24 | ), 25 | ), 26 | vSpace(30), 27 | Padding( 28 | padding: const EdgeInsets.symmetric(horizontal: 20), 29 | child: Button( 30 | text: 'Retry', 31 | onTap: onTap, 32 | ), 33 | ), 34 | ], 35 | ), 36 | ), 37 | ], 38 | ), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/shared_widgets/movies_grid.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | 5 | class MoviesGrid extends StatelessWidget { 6 | const MoviesGrid({ 7 | super.key, 8 | this.movies, 9 | required this.genreTitle, 10 | }); 11 | 12 | final List? movies; 13 | final String genreTitle; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return GridView.builder( 18 | itemCount: movies?.length ?? 0, 19 | gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( 20 | crossAxisCount: 4, 21 | childAspectRatio: 111 / 180, 22 | crossAxisSpacing: kfsTiny, 23 | mainAxisSpacing: kfsMedium, 24 | ), 25 | itemBuilder: (context, int index) { 26 | final id = '$genreTitle${movies?[index].name}${movies?[index].id}'; 27 | return Hero( 28 | tag: id, 29 | child: MovieCardTile( 30 | imageUrl: movies?[index].posterPath ?? '', 31 | onTap: () => goTo( 32 | MovieDetailsScreen.route, 33 | arguments: MovieDetailsParams( 34 | genreTitle: genreTitle, 35 | movieResults: movies?[index], 36 | ), 37 | ), 38 | ), 39 | ); 40 | }, 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/movie_details.dart: -------------------------------------------------------------------------------- 1 | export 'presentation/views/movie_details_screen.dart'; 2 | export 'presentation/components/movie_details_header.dart'; 3 | export 'domain/entities/movie_details_entity.dart'; 4 | export 'domain/repo/movie_detail_repo.dart'; 5 | export 'data/repo-impl/movie_detail_repo_impl.dart'; 6 | export 'data/datasource/remote_data_source.dart'; 7 | export 'data/model/movie_details_model.dart'; 8 | export 'domain/usecase/get_movie_detail_usecase.dart'; 9 | export 'presentation/notifier/movie_details_notifier.dart'; 10 | export 'movie_details_locator.dart'; 11 | export 'domain/entities/image_entity.dart'; 12 | export 'data/model/image_model.dart'; 13 | export 'domain/usecase/get_images_usecase.dart'; 14 | export 'presentation/components/image_preview_page.dart'; 15 | export 'presentation/atoms/grid_view.dart'; 16 | export 'presentation/notifier/image_notifier.dart'; 17 | export 'domain/usecase/get_similar_movies_usecase.dart'; 18 | export 'presentation/notifier/similar_movies_notifier.dart'; 19 | export 'presentation/atoms/movie_details_body.dart'; 20 | export 'presentation/components/movie_info.dart'; 21 | export 'presentation/atoms/similar_movies.dart'; 22 | export 'presentation/atoms/watch_movie_button.dart'; 23 | export 'presentation/components/images_section.dart'; 24 | export 'domain/usecase/is_movie_a_watchlist_usecase.dart'; 25 | export 'presentation/notifier/check_movie_is_a_watchlist_notifier.dart'; 26 | -------------------------------------------------------------------------------- /movie_hub/windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.Create(L"movie_hub", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/shared_widgets/movie_card_tile.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/home/home.dart'; 4 | 5 | class MovieCardTile extends StatefulWidget { 6 | const MovieCardTile({ 7 | super.key, 8 | required this.imageUrl, 9 | required this.onTap, 10 | this.height, 11 | this.margin, 12 | }); 13 | final String imageUrl; 14 | final VoidCallback onTap; 15 | final double? height; 16 | final EdgeInsets? margin; 17 | 18 | @override 19 | State createState() => _MovieCardTileState(); 20 | } 21 | 22 | class _MovieCardTileState extends State { 23 | @override 24 | Widget build(BuildContext context) { 25 | return GestureDetector( 26 | onTap: widget.onTap, 27 | child: Container( 28 | height: widget.height ?? kXtremeLarge, 29 | width: 100, 30 | decoration: BoxDecoration( 31 | borderRadius: BorderRadius.circular(kfsTiny), 32 | color: kcGrey.withOpacity(.3), 33 | ), 34 | child: ClipRRect( 35 | borderRadius: BorderRadius.circular(kfsTiny), 36 | child: ImageWidget( 37 | imageTypes: ImageTypes.network, 38 | imageUrl: widget.imageUrl, 39 | fit: BoxFit.cover, 40 | loader: const ShimmerWidget(), 41 | ), 42 | ), 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /movie_hub/assets/icons/mail.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/data/repo_impl/search_movies_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | 5 | class SearchMovieImpl extends SearchMoviesRepository { 6 | final SearchMovieDataSource searchMovieDataSource; 7 | 8 | SearchMovieImpl({ 9 | required this.searchMovieDataSource, 10 | }); 11 | 12 | @override 13 | FutureOr> discoverMovies(int page) { 14 | return _handleSearchMovieOperation( 15 | () => searchMovieDataSource.discoverMovies(page), 16 | ); 17 | } 18 | 19 | @override 20 | FutureOr> searchMovies( 21 | SearchParamsModel params, 22 | ) { 23 | return _handleSearchMovieOperation( 24 | () => searchMovieDataSource.searchMovies(params), 25 | ); 26 | } 27 | 28 | Future> _handleSearchMovieOperation( 29 | Future Function() operation, 30 | ) async { 31 | try { 32 | final T result = await operation(); 33 | 34 | return Either.right(result); 35 | } on SocketFailures { 36 | return const Left(BaseFailures(message: ErrorText.noInternet)); 37 | } catch (e, s) { 38 | AppLogger.log(e, s); 39 | 40 | if (e is BaseFailures) { 41 | return Either.left(BaseFailures(message: e.message)); 42 | } 43 | 44 | return Either.left(BaseFailures(message: e.toString())); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/notifier/popular_movies_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/features/movies/home/home.dart'; 3 | 4 | class PopularMoviesNotifier extends ChangeNotifier { 5 | final PopularMoviesUsecase popularMoviesUsecase; 6 | 7 | PopularMoviesNotifier({ 8 | required this.popularMoviesUsecase, 9 | }); 10 | 11 | int _page = 1; 12 | final List _movies = []; 13 | List? get popularMovies => _movies; 14 | 15 | Future getPopularMovies({bool shouldFetch = false}) async { 16 | _setPopularMovieState(PopularMovieState.isLoading); 17 | 18 | if (shouldFetch) { 19 | _page++; 20 | notifyListeners(); 21 | } 22 | final popularMoviesResponse = await popularMoviesUsecase.call(_page); 23 | 24 | popularMoviesResponse.fold( 25 | (l) { 26 | _setPopularMovieState(PopularMovieState.isError); 27 | }, 28 | (r) { 29 | _movies.addAll(r.results ?? []); 30 | notifyListeners(); 31 | _setPopularMovieState(PopularMovieState.isDone); 32 | }, 33 | ); 34 | } 35 | 36 | PopularMovieState _popularMovieState = PopularMovieState.isDone; 37 | PopularMovieState get popularMovieState => _popularMovieState; 38 | 39 | void _setPopularMovieState(PopularMovieState state) { 40 | _popularMovieState = state; 41 | notifyListeners(); 42 | } 43 | } 44 | 45 | enum PopularMovieState { isLoading, isError, isDone } 46 | -------------------------------------------------------------------------------- /movie_hub/macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.14' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/notifier/upcoming_movies_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/features/movies/home/home.dart'; 3 | 4 | class UpcomingMoviesNotifier extends ChangeNotifier { 5 | final GetUpcomingMoviesUseCase upcomingMoviesNotifier; 6 | 7 | UpcomingMoviesNotifier({ 8 | required this.upcomingMoviesNotifier, 9 | }); 10 | 11 | int _page = 1; 12 | final List _movies = []; 13 | List? get upcomingMovies => _movies; 14 | 15 | Future getUpcomingMovies({bool shouldFetch = false}) async { 16 | _setUpcomingMoviesState(UpcomingMoviesState.isLoading); 17 | if (shouldFetch) { 18 | _page++; 19 | notifyListeners(); 20 | } 21 | final res = await upcomingMoviesNotifier.call(_page); 22 | 23 | res.fold( 24 | (l) { 25 | _setUpcomingMoviesState(UpcomingMoviesState.isError); 26 | }, 27 | (r) { 28 | _movies.addAll(r.results ?? []); 29 | notifyListeners(); 30 | _setUpcomingMoviesState(UpcomingMoviesState.isDone); 31 | }, 32 | ); 33 | } 34 | 35 | UpcomingMoviesState _upcomingMoviesState = UpcomingMoviesState.isDone; 36 | UpcomingMoviesState get upcomingMoviesState => _upcomingMoviesState; 37 | 38 | void _setUpcomingMoviesState(UpcomingMoviesState state) { 39 | _upcomingMoviesState = state; 40 | notifyListeners(); 41 | } 42 | } 43 | 44 | enum UpcomingMoviesState { isLoading, isError, isDone } 45 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/presentation/notifier/movie_details_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fpdart/fpdart.dart'; 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/movies/movie_details/movie_details.dart'; 5 | 6 | class MovieDetailsNotifier extends ChangeNotifier { 7 | final MovieDetailUsecase movieDetailsUsecase; 8 | 9 | MovieDetailsNotifier({ 10 | required this.movieDetailsUsecase, 11 | }); 12 | 13 | MovieDetailModel? _movieDetail; 14 | MovieDetailModel? get movieDetail => _movieDetail; 15 | 16 | Future> getMovieDetails( 17 | String movieId, 18 | ) async { 19 | _setMovieDetailState(MovieDetailState.isLoading); 20 | final res = await movieDetailsUsecase.call(movieId); 21 | 22 | return res.fold( 23 | (l) { 24 | _setMovieDetailState(MovieDetailState.isError); 25 | return Left(l); 26 | }, 27 | (r) { 28 | _movieDetail = r; 29 | notifyListeners(); 30 | _setMovieDetailState(MovieDetailState.isDone); 31 | return Right(r); 32 | }, 33 | ); 34 | } 35 | 36 | MovieDetailState _movieDetailState = MovieDetailState.isDone; 37 | MovieDetailState get movieDetailState => _movieDetailState; 38 | 39 | void _setMovieDetailState(MovieDetailState state) { 40 | _movieDetailState = state; 41 | notifyListeners(); 42 | } 43 | } 44 | 45 | enum MovieDetailState { isLoading, isError, isDone } 46 | -------------------------------------------------------------------------------- /movie_hub/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '11.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/notifier/top_rated_movies_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/features/movies/home/home.dart'; 3 | 4 | class TopRatedMoviesNotifier extends ChangeNotifier { 5 | final TopRatedMoviesUseCase topRatedMoviesUseCase; 6 | 7 | TopRatedMoviesNotifier({ 8 | required this.topRatedMoviesUseCase, 9 | }); 10 | 11 | int _page = 1; 12 | final List _movies = []; 13 | List? get topRatedMovies => _movies; 14 | 15 | Future getTopRatedMovies({bool shouldFetch = false}) async { 16 | _setTopRatedMoviesState(TopRatedMoviesState.isLoading); 17 | if (shouldFetch) { 18 | _page++; 19 | notifyListeners(); 20 | } 21 | final topRatedMoviesResponse = await topRatedMoviesUseCase.call(_page); 22 | topRatedMoviesResponse.fold( 23 | (l) { 24 | _setTopRatedMoviesState(TopRatedMoviesState.isError); 25 | }, 26 | (r) { 27 | _movies.addAll(r.results ?? []); 28 | notifyListeners(); 29 | _setTopRatedMoviesState(TopRatedMoviesState.isDone); 30 | }, 31 | ); 32 | } 33 | 34 | TopRatedMoviesState _topRatedMoviesState = TopRatedMoviesState.isDone; 35 | TopRatedMoviesState get topRatedMoviesState => _topRatedMoviesState; 36 | 37 | void _setTopRatedMoviesState(TopRatedMoviesState state) { 38 | _topRatedMoviesState = state; 39 | notifyListeners(); 40 | } 41 | } 42 | 43 | enum TopRatedMoviesState { isLoading, isError, isDone } 44 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/shared/cached_network_image_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:movie_hub/cores/cores.dart'; 4 | 5 | class CachedNetworkImageWidget extends StatefulWidget { 6 | const CachedNetworkImageWidget({ 7 | super.key, 8 | required this.url, 9 | this.radius, 10 | this.height, 11 | this.fit, 12 | this.width, 13 | this.loader, 14 | }); 15 | 16 | final String url; 17 | final double? radius; 18 | final double? height; 19 | final double? width; 20 | final BoxFit? fit; 21 | final Widget? loader; 22 | 23 | @override 24 | State createState() => _CachedNetworkImageWidgetState(); 25 | } 26 | 27 | class _CachedNetworkImageWidgetState extends State { 28 | @override 29 | Widget build(BuildContext context) { 30 | return ClipRRect( 31 | borderRadius: BorderRadius.circular(widget.radius ?? 0), 32 | child: CachedNetworkImage( 33 | imageUrl: widget.url, 34 | fadeOutCurve: Curves.easeInCirc, 35 | httpHeaders: const {'timeout': '30'}, 36 | fit: widget.fit, 37 | height: widget.height, 38 | errorWidget: (_, __, ___) => Container( 39 | color: kcWhiteColor, 40 | child: const Center( 41 | child: Icon(Icons.error), 42 | ), 43 | ), 44 | placeholder: (_, __) => widget.loader ?? const LoadingWidget(), 45 | ), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/profile_locator.dart: -------------------------------------------------------------------------------- 1 | import 'package:movie_hub/cores/cores.dart'; 2 | import 'package:movie_hub/features/profile/profile.dart'; 3 | 4 | void setUpProfileLocator() { 5 | getIt.registerLazySingleton( 6 | () => ProfileDataSourceImpl( 7 | firebaseHelper: FirebaseHelper(), 8 | ), 9 | ); 10 | 11 | getIt.registerLazySingleton( 12 | () => ProfileRepoImpl( 13 | profileDataSource: getIt(), 14 | ), 15 | ); 16 | 17 | getIt.registerLazySingleton( 18 | () => FetchProfileDetailsUsecase( 19 | profileRepo: getIt(), 20 | ), 21 | ); 22 | 23 | getIt.registerLazySingleton( 24 | () => FetchAvatarsUsecase( 25 | profileRepo: getIt(), 26 | ), 27 | ); 28 | 29 | getIt.registerLazySingleton( 30 | () => UpdateAvatarUsecase( 31 | profileRepo: getIt(), 32 | ), 33 | ); 34 | 35 | getIt.registerLazySingleton( 36 | () => FetchProfileNotifier( 37 | fetchProfileUsecase: getIt(), 38 | ), 39 | ); 40 | 41 | getIt.registerLazySingleton( 42 | () => FetchAvatarNotifier( 43 | fetchAvatarsUsecase: getIt(), 44 | ), 45 | ); 46 | 47 | getIt.registerLazySingleton( 48 | () => UpdateAvatarNotifier( 49 | updateUsecase: getIt(), 50 | ), 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /movie_hub/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/usecase/usecase_interface.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:fpdart/fpdart.dart'; 4 | 5 | /// `UseCase` for getting data with Future. 6 | /// 7 | /// Use case contains the app's business logic / rules, e.g. validations. 8 | /// It should be independent from any other non-business logic-related 9 | /// functionalities. 10 | /// 11 | /// It can be connected with repository, although not every use case needs to 12 | /// depend on the repository. 13 | /// 14 | /// If you can live with less static typing, you can use `Params` type 15 | /// as Params. 16 | /// 17 | abstract class UseCaseFuture { 18 | /// Method to calling this useCase 19 | FutureOr> call(Params params); 20 | } 21 | 22 | abstract class UseCaseVoid { 23 | /// Method to calling this useCase 24 | FutureOr> call(Params params); 25 | } 26 | 27 | /// `UseCase` for getting data with Stream. 28 | /// This usecase for getting data realtime. 29 | /// 30 | /// Use case contains the app's business logic / rules, e.g. validations. 31 | /// It should be independent from any other non-business logic-related 32 | /// functionalities. 33 | /// 34 | /// It can be connected with repository, although not every use case needs to 35 | /// depend on the repository. 36 | /// 37 | /// If you can live with less static typing, you can use `Params` type 38 | /// as Params. 39 | /// 40 | abstract class UseCaseStream { 41 | /// Method to calling this useCase 42 | Stream> call(Params params); 43 | } 44 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/presentation/notifier/discover_movies_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 3 | 4 | class DiscoverMoviesNotifier extends ChangeNotifier { 5 | final DiscoverMoviesUsecase discoverMoviesUsecase; 6 | DiscoverMoviesNotifier({ 7 | required this.discoverMoviesUsecase, 8 | }); 9 | 10 | int _page = 1; 11 | final List _movies = []; 12 | List get discoveredMovies => _movies; 13 | 14 | Future discoverMovies({bool shouldFetch = false}) async { 15 | if (!shouldFetch) { 16 | _setDiscoverMovieState(DiscoverMovieState.loading); 17 | } 18 | if (shouldFetch) { 19 | _page++; 20 | notifyListeners(); 21 | } 22 | 23 | final discoveredMoviesResponse = await discoverMoviesUsecase.call(_page); 24 | 25 | discoveredMoviesResponse.fold( 26 | (l) { 27 | _setDiscoverMovieState(DiscoverMovieState.error); 28 | }, 29 | (moviesModel) { 30 | final discoveredMovies = moviesModel.results ?? []; 31 | _movies.addAll(discoveredMovies); 32 | notifyListeners(); 33 | _setDiscoverMovieState(DiscoverMovieState.idle); 34 | }, 35 | ); 36 | } 37 | 38 | DiscoverMovieState _discoverMovieState = DiscoverMovieState.idle; 39 | 40 | DiscoverMovieState get discoverMovieState => _discoverMovieState; 41 | 42 | void _setDiscoverMovieState(DiscoverMovieState state) { 43 | _discoverMovieState = state; 44 | notifyListeners(); 45 | } 46 | } 47 | 48 | enum DiscoverMovieState { idle, error, loading } 49 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/atoms/upcoming_movies_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | class UpcomingMoviesSection extends StatelessWidget { 7 | const UpcomingMoviesSection({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Consumer( 12 | builder: (_, viewModel, __) { 13 | return viewModel.upcomingMovies?.isEmpty ?? true 14 | ? const SizedBox.shrink() 15 | : SizedBox( 16 | child: switch (viewModel.upcomingMoviesState) { 17 | UpcomingMoviesState.isLoading => const SizedBox.shrink(), 18 | UpcomingMoviesState.isError => const SizedBox.shrink(), 19 | UpcomingMoviesState.isDone => GenreCardWidget( 20 | title: 'UPCOMING MOVIES', 21 | movies: viewModel.upcomingMovies, 22 | onNotification: (notification) { 23 | if (notification is ScrollEndNotification && 24 | notification.metrics.extentAfter == 0) { 25 | context.upcomingMovies.getUpcomingMovies( 26 | shouldFetch: true, 27 | ); 28 | } 29 | return true; 30 | }, 31 | ), 32 | }, 33 | ); 34 | }, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /movie_hub/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/shared/app_bar_widget.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:movie_hub/cores/navigator/app_router.dart'; 5 | import 'package:movie_hub/cores/utils/sizer.dart'; 6 | 7 | class AppBarWidget extends StatelessWidget { 8 | const AppBarWidget({ 9 | super.key, 10 | required this.title, 11 | required this.showBackButton, 12 | this.trailing, 13 | required this.useSpacer, 14 | }); 15 | final String title; 16 | final bool showBackButton; 17 | final Widget? trailing; 18 | final bool useSpacer; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Row( 23 | children: [ 24 | if (showBackButton) 25 | GestureDetector( 26 | onTap: goBack, 27 | child: Padding( 28 | padding: EdgeInsets.only( 29 | right: sp(showBackButton ? 20.0 : 40), 30 | top: sp(20.0), 31 | bottom: sp(20.0), 32 | ), 33 | child: Center( 34 | child: Icon( 35 | Platform.isIOS 36 | ? Icons.arrow_back_ios_new_rounded 37 | : Icons.arrow_back, 38 | size: sp(20), 39 | ), 40 | ), 41 | ), 42 | ) 43 | else 44 | const SizedBox.shrink(), 45 | if (useSpacer) const Spacer(), 46 | // TextWidget(title, fontSize: sp(24)), 47 | Text(title), 48 | if (useSpacer) const Spacer(), 49 | trailing ?? SizedBox(height: sp(20), width: sp(40)), 50 | ], 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/atoms/trending_for_the_day.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | class TrendingForTheDaySection extends StatelessWidget { 7 | const TrendingForTheDaySection({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Consumer( 12 | builder: (_, viewModel, __) { 13 | return viewModel.trendingMovies?.isEmpty??true 14 | ? const SizedBox.shrink() 15 | : SizedBox( 16 | child: switch (viewModel.trendingMoviesForTheDay) { 17 | TrendingForTheDayState.isLoading => const SizedBox.shrink(), 18 | TrendingForTheDayState.isError => const SizedBox.shrink(), 19 | TrendingForTheDayState.isDone => GenreCardWidget( 20 | title: 'TRENDING FOR THE DAY', 21 | movies: viewModel.trendingMovies, 22 | onNotification: (notification) { 23 | if (notification is ScrollEndNotification && 24 | notification.metrics.extentAfter == 0) { 25 | context.trendingMovies.getTrendingMoviesForTheDay( 26 | shouldFetch: true, 27 | ); 28 | } 29 | return true; 30 | }, 31 | ), 32 | }, 33 | ); 34 | }, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/watchlist/presentation/notifier/watchlist_movie_details_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_details/movie_details.dart'; 4 | 5 | class WatchListDetailsNotifier extends ChangeNotifier { 6 | final MovieDetailUsecase _movieDetailUsecase; 7 | 8 | WatchListDetailsNotifier({ 9 | required MovieDetailUsecase movieDetailUsecase, 10 | }) : _movieDetailUsecase = movieDetailUsecase; 11 | 12 | final List _allWatchList = []; 13 | List? get allWatchList => _allWatchList; 14 | 15 | Future getWatchListMovieDetail() async { 16 | /// Get all watchlist movie Ids 17 | /// 18 | final List watchlistId = 19 | navigatorKey.currentContext!.getWatchListId.allMovieIds; 20 | 21 | for (var id in watchlistId) { 22 | _setWatchListState(WatchListState.loading); 23 | 24 | final res = await _movieDetailUsecase.call(id); 25 | 26 | res.fold( 27 | (l) { 28 | _setWatchListState(WatchListState.error); 29 | }, 30 | (MovieDetailModel r) { 31 | _allWatchList.add(r); 32 | _setWatchListState(WatchListState.isDone); 33 | }, 34 | ); 35 | } 36 | notifyListeners(); 37 | } 38 | 39 | WatchListState _watchListState = WatchListState.isDone; 40 | 41 | WatchListState get watchListState => _watchListState; 42 | 43 | void _setWatchListState(WatchListState state) { 44 | _watchListState = state; 45 | notifyListeners(); 46 | } 47 | } 48 | 49 | enum WatchListState { isDone, loading, error } 50 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/atoms/top_rated_movies_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/home/home.dart'; 4 | import 'package:movie_hub/features/movies/shared_widgets/widgets.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class TopRatedMoviesSection extends StatelessWidget { 8 | const TopRatedMoviesSection({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Consumer( 13 | builder: (_, viewModel, __) { 14 | return (viewModel.topRatedMovies?.isEmpty ?? true) 15 | ? const SizedBox.shrink() 16 | : SizedBox( 17 | child: switch (viewModel.topRatedMoviesState) { 18 | TopRatedMoviesState.isLoading => const SizedBox.shrink(), 19 | TopRatedMoviesState.isError => const SizedBox.shrink(), 20 | TopRatedMoviesState.isDone => GenreCardWidget( 21 | title: 'TOP RATED', 22 | movies: viewModel.topRatedMovies, 23 | onNotification: (notification) { 24 | if (notification is ScrollEndNotification && 25 | notification.metrics.extentAfter == 0) { 26 | context.topRated.getTopRatedMovies( 27 | shouldFetch: true, 28 | ); 29 | } 30 | return true; 31 | }, 32 | ), 33 | }, 34 | ); 35 | }, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /movie_hub/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 | -------------------------------------------------------------------------------- /movie_hub/lib/cores/utils/exception/firebase_auth_exception.dart: -------------------------------------------------------------------------------- 1 | import 'base_exception.dart'; 2 | 3 | class AuthFirebaseException extends BaseFailures { 4 | const AuthFirebaseException(this.errorCode, [this.stackTrack]) 5 | : super(message: ""); 6 | 7 | final String errorCode; 8 | final StackTrace? stackTrack; 9 | 10 | @override 11 | String get message => _getMessage(); 12 | 13 | String _getMessage() { 14 | switch (errorCode) { 15 | case "ERROR_EMAIL_ALREADY_IN_USE": 16 | case "account-exists-with-different-credential": 17 | case "email-already-in-use": 18 | return "Email already used. Go to login page."; 19 | 20 | case "ERROR_WRONG_PASSWORD": 21 | case "wrong-password": 22 | return "Wrong email/password combination."; 23 | 24 | case "ERROR_USER_NOT_FOUND": 25 | case "user-not-found": 26 | return "No user found with this email."; 27 | 28 | case "ERROR_USER_DISABLED": 29 | case "user-disabled": 30 | return "User disabled."; 31 | 32 | case "ERROR_TOO_MANY_REQUESTS": 33 | case "too-many-request": 34 | return "Too many requests to log into this account."; 35 | 36 | case "ERROR_OPERATION_NOT_ALLOWED": 37 | case "operation-not-allowed": 38 | return "Server error, please try again later."; 39 | 40 | case "ERROR_INVALID_EMAIL": 41 | case "invalid-email": 42 | return "Email address is invalid."; 43 | 44 | case "weak-password": 45 | return "Password should be at least 6 characters."; 46 | case "INVALID_LOGIN_CREDENTIALS": 47 | return "Wrong email/password combination"; 48 | default: 49 | return "Something went wrong, Try Again."; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/atoms/popular_movies_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/home/presentation/notifier/popular_movies_notifier.dart'; 4 | import 'package:movie_hub/features/movies/shared_widgets/genre_card_widget.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class PopularMoviesSection extends StatelessWidget { 8 | const PopularMoviesSection({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Consumer( 13 | builder: (_, viewModel, __) { 14 | return viewModel.popularMovies?.isEmpty ?? true 15 | ? const SizedBox.shrink() 16 | : SizedBox( 17 | child: switch (viewModel.popularMovieState) { 18 | PopularMovieState.isLoading => const SizedBox.shrink(), 19 | PopularMovieState.isError => const SizedBox.shrink(), 20 | PopularMovieState.isDone => GenreCardWidget( 21 | title: 'POPULAR MOVIES', 22 | movies: viewModel.popularMovies, 23 | onNotification: (notification) { 24 | if (notification is ScrollEndNotification && 25 | notification.metrics.extentAfter == 0) { 26 | context.popularMovies.getPopularMovies( 27 | shouldFetch: true, 28 | ); 29 | } 30 | return true; 31 | }, 32 | ), 33 | }, 34 | ); 35 | }, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/atoms/trending_for_the_week_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | class TrendingForTheWeekSection extends StatelessWidget { 7 | const TrendingForTheWeekSection({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Consumer( 12 | builder: (_, viewModel, __) { 13 | return viewModel.trendingForTheWeekMovies?.isEmpty??true 14 | ? const SizedBox.shrink() 15 | : SizedBox( 16 | child: switch (viewModel.trendingForTheWeekState) { 17 | TrendingForTheWeekState.isLoading => const SizedBox.shrink(), 18 | TrendingForTheWeekState.isError => const SizedBox.shrink(), 19 | TrendingForTheWeekState.isDone => GenreCardWidget( 20 | title: 'TRENDING FOR THE WEEK', 21 | movies: viewModel.trendingForTheWeekMovies, 22 | onNotification: (notification) { 23 | if (notification is ScrollEndNotification && 24 | notification.metrics.extentAfter == 0) { 25 | context.trendingForTheWeek 26 | .getTrendingMoviesForTheWeek( 27 | shouldFetch: true, 28 | ); 29 | } 30 | return true; 31 | }, 32 | ), 33 | }, 34 | ); 35 | }, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/data/datasource/home_remote_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:movie_hub/cores/cores.dart'; 2 | import 'package:movie_hub/features/movies/home/home.dart'; 3 | 4 | abstract class HomeRemoteDataSource { 5 | Future getTrendingMovies( 6 | String timeWindow, 7 | int page, 8 | ); 9 | Future getPopularMovies(int page); 10 | Future getRatedMovies(int page); 11 | Future getUpcomingMovie(int page); 12 | } 13 | 14 | class HomeRemoteDataSourceImpl extends HomeRemoteDataSource { 15 | /// Fetches trending movies for a particular time period 16 | /// [timeWindow] could be DAY or WEEK. 17 | @override 18 | Future getTrendingMovies( 19 | String timeWindow, 20 | int page, 21 | ) async { 22 | return await _getMovies('/trending/movie/$timeWindow', page); 23 | } 24 | 25 | /// Fetches movies ordered by popularity. 26 | @override 27 | Future getPopularMovies(int page) async { 28 | return await _getMovies('/movie/popular', page); 29 | } 30 | 31 | /// Fetches rated movies. 32 | @override 33 | Future getRatedMovies(int page) async { 34 | return await _getMovies('/movie/top_rated', page); 35 | } 36 | 37 | ///Fetches upcoming movie 38 | @override 39 | Future getUpcomingMovie(int page) async { 40 | return await _getMovies('/movie/upcoming', page); 41 | } 42 | } 43 | 44 | /// Fetches all Movies of different [tag] 45 | Future _getMovies(String tag, int page) async { 46 | final String url = '$baseUrl$tag'; 47 | final result = await HttpHelper.get(url, query: { 48 | 'page': page, 49 | }); 50 | final MoviesModel movies = MoviesModel.fromJson(result); 51 | return movies; 52 | } 53 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/discover/presentation/components/search_movies_grid.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 4 | import 'package:movie_hub/features/movies/shared_widgets/movies_grid.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class SearchMoviesGrid extends StatelessWidget { 8 | const SearchMoviesGrid({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Consumer( 13 | builder: (_, viewModel, __) { 14 | return Visibility( 15 | visible: viewModel.searchedMovies.isNotEmpty, 16 | replacement: const MovieNotFound(), 17 | child: switch (viewModel.searchState) { 18 | SearchState.isLoading => const LoadingWidget(), 19 | SearchState.isDone => NotificationListener( 20 | onNotification: (notification) { 21 | if (notification is ScrollEndNotification && 22 | notification.metrics.extentAfter == 0) { 23 | context.search.searchMovies( 24 | shouldFetch: true, 25 | ); 26 | } 27 | return false; 28 | }, 29 | child: MoviesGrid( 30 | movies: viewModel.searchedMovies, 31 | genreTitle: 'Search', 32 | ), 33 | ), 34 | SearchState.isError => PageErrorWidget( 35 | onTap: () => viewModel.updateSearchValue( 36 | viewModel.searchedValue.toString(), 37 | ), 38 | ), 39 | }, 40 | ); 41 | }, 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /movie_hub/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/data/model/image_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:movie_hub/cores/cores.dart'; 2 | import 'package:movie_hub/features/movies/movie_details/movie_details.dart'; 3 | 4 | class ImageModel extends ImageEntity { 5 | const ImageModel({ 6 | required super.backdrops, 7 | required super.id, 8 | required super.logos, 9 | required super.posters, 10 | }); 11 | 12 | factory ImageModel.fromJson(Mapped json) { 13 | return ImageModel( 14 | backdrops: json['backdrops'] != null 15 | ? (json['backdrops'] as List) 16 | .map((e) => BackdropModel.fromJson(e)) 17 | .toList() 18 | : [], 19 | id: json['id'], 20 | logos: json['logo'] != null 21 | ? (json['logo'] as List) 22 | .map((e) => BackdropModel.fromJson(e)) 23 | .toList() 24 | : [], 25 | posters: json['posters'] != null 26 | ? (json['posters'] as List) 27 | .map((e) => BackdropModel.fromJson(e)) 28 | .toList() 29 | : [], 30 | ); 31 | } 32 | } 33 | 34 | class BackdropModel extends BackdropEntity { 35 | const BackdropModel( 36 | {required super.aspectRatio, 37 | required super.filePath, 38 | required super.height, 39 | required super.iso6391, 40 | required super.voteAverage, 41 | required super.voteCount, 42 | required super.width}); 43 | 44 | factory BackdropModel.fromJson(Mapped json) { 45 | return BackdropModel( 46 | aspectRatio: json['aspect_ratio'], 47 | filePath: json['file_path'], 48 | height: json['height'], 49 | iso6391: json['iso_639_1'], 50 | voteAverage: json['vote_average'], 51 | voteCount: json['vote_count'], 52 | width: json['width'], 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /movie_hub/.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: b06b8b2710955028a6b562f5aa6fe62941d6febf 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: b06b8b2710955028a6b562f5aa6fe62941d6febf 17 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 18 | - platform: android 19 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 20 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 21 | - platform: ios 22 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 23 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 24 | - platform: linux 25 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 26 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 27 | - platform: macos 28 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 29 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 30 | - platform: web 31 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 32 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 33 | - platform: windows 34 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 35 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 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 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/components/see_all_movies.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/home/home.dart'; 4 | import 'package:movie_hub/features/movies/shared_widgets/movies_grid.dart'; 5 | 6 | class SeeAllMovies extends StatefulWidget { 7 | static const String route = '/see-all-movies'; 8 | 9 | const SeeAllMovies({ 10 | super.key, 11 | required this.params, 12 | }); 13 | 14 | final SeeAllParams params; 15 | 16 | @override 17 | State createState() => _SeeAllMoviesState(); 18 | } 19 | 20 | class _SeeAllMoviesState extends State { 21 | bool shouldTriggerRebuild = false; 22 | @override 23 | Widget build(BuildContext context) { 24 | return ScaffoldWidget( 25 | appBar: AppBar( 26 | backgroundColor: kcBackground, 27 | elevation: 0, 28 | title: TextWidget( 29 | widget.params.genreTitle, 30 | fontWeight: FontWeight.w700, 31 | ), 32 | ), 33 | body: Padding( 34 | padding: const EdgeInsets.fromLTRB( 35 | kfsExtraLarge, 36 | kfsExtraLarge, 37 | kfsExtraLarge, 38 | 0, 39 | ), 40 | child: NotificationListener( 41 | onNotification: (Notification notification) { 42 | widget.params.handleNotification(notification); 43 | setState(() { 44 | shouldTriggerRebuild = false; 45 | }); 46 | 47 | return true; 48 | }, 49 | child: MoviesGrid( 50 | movies: widget.params.movies, 51 | genreTitle: 'SEE ALL${widget.params.genreTitle}', 52 | ), 53 | ), 54 | ), 55 | useSingleScroll: false, 56 | usePadding: false, 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/notifier/trending_movies_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 3 | 4 | class TrendingMoviesNotifier extends ChangeNotifier { 5 | final TrendingMoviesUseCase trendingMovieUsecase; 6 | 7 | TrendingMoviesNotifier({ 8 | required this.trendingMovieUsecase, 9 | }); 10 | 11 | int _page = 1; 12 | final List _movies = []; 13 | List? get trendingMovies => _movies; 14 | 15 | Future getTrendingMoviesForTheDay({bool shouldFetch = false}) async { 16 | await _getTrendingMovies('day', shouldFetch: shouldFetch); 17 | } 18 | 19 | Future _getTrendingMovies( 20 | String timeWindow, { 21 | bool shouldFetch = false, 22 | }) async { 23 | _setTrendingForTheDayState(TrendingForTheDayState.isLoading); 24 | if (shouldFetch) { 25 | _page++; 26 | notifyListeners(); 27 | } 28 | final trendingMoviesResponse = await trendingMovieUsecase.call( 29 | TrendingMoviesParams(timeWindow: timeWindow, page: _page), 30 | ); 31 | trendingMoviesResponse.fold( 32 | (l) { 33 | _setTrendingForTheDayState(TrendingForTheDayState.isError); 34 | }, 35 | (r) { 36 | _movies.addAll(r.results ?? []); 37 | notifyListeners(); 38 | _setTrendingForTheDayState(TrendingForTheDayState.isDone); 39 | }, 40 | ); 41 | } 42 | 43 | TrendingForTheDayState _trendingForTheDayState = 44 | TrendingForTheDayState.isDone; 45 | TrendingForTheDayState get trendingMoviesForTheDay => _trendingForTheDayState; 46 | 47 | void _setTrendingForTheDayState(TrendingForTheDayState state) { 48 | _trendingForTheDayState = state; 49 | notifyListeners(); 50 | } 51 | } 52 | 53 | enum TrendingForTheDayState { isLoading, isError, isDone } 54 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/presentation/atoms/similar_movies.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_details/movie_details.dart'; 4 | import 'package:movie_hub/features/movies/shared_widgets/widgets.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class SimilarMovies extends StatefulWidget { 8 | const SimilarMovies({super.key, required this.movieId}); 9 | final String movieId; 10 | 11 | @override 12 | State createState() => _SimilarMoviesState(); 13 | } 14 | 15 | class _SimilarMoviesState extends State { 16 | 17 | @override 18 | void initState() { 19 | super.initState(); 20 | WidgetsBinding.instance.addPostFrameCallback( 21 | (timeStamp) { 22 | context.similarMovies.getSimilarMovies(widget.movieId); 23 | }, 24 | ); 25 | } 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | return Consumer( 30 | builder: (context, viewModel, _) { 31 | return Column( 32 | children: [ 33 | switch (viewModel.similarMoviesState) { 34 | SimilarMoviesState.isLoading => const LoadingWidget(), 35 | SimilarMoviesState.isError => const SizedBox.shrink(), 36 | SimilarMoviesState.isDone => Visibility( 37 | visible: viewModel.similarMovies?.results?.isNotEmpty ?? true, 38 | child: GenreCardWidget( 39 | padding: EdgeInsets.zero, 40 | title: 'Similar Movies', 41 | movies: viewModel.similarMovies?.results, 42 | fontWeight: FontWeight.w700, 43 | ), 44 | ) 45 | } 46 | ], 47 | ); 48 | }, 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/movie_details/presentation/components/movie_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:movie_hub/cores/cores.dart'; 3 | import 'package:movie_hub/features/movies/movie_details/movie_details.dart'; 4 | import 'package:movie_hub/features/movies/shared_widgets/widgets.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class MovieInfo extends StatefulWidget { 8 | const MovieInfo({ 9 | super.key, 10 | required this.movieId, 11 | required this.movies, 12 | }); 13 | final String movieId; 14 | final MovieDetailsParams movies; 15 | 16 | @override 17 | State createState() => _MovieInfoState(); 18 | } 19 | 20 | class _MovieInfoState extends State { 21 | 22 | @override 23 | void initState() { 24 | WidgetsBinding.instance.addPostFrameCallback( 25 | (timeStamp) { 26 | context.movieDetails.getMovieDetails(widget.movieId); 27 | }, 28 | ); 29 | super.initState(); 30 | } 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | return Consumer( 35 | builder: (context, viewModel, _) { 36 | return Column( 37 | children: [ 38 | switch (viewModel.movieDetailState) { 39 | MovieDetailState.isLoading => const LoadingWidget(), 40 | MovieDetailState.isError => PageErrorWidget( 41 | onTap: () { 42 | context.movieDetails.getMovieDetails(widget.movieId); 43 | }, 44 | ), 45 | MovieDetailState.isDone => MovieInfoAtom( 46 | movies: widget.movies, 47 | movieDetails: viewModel.movieDetail, 48 | movieId: widget.movieId, 49 | ), 50 | } 51 | ], 52 | ); 53 | }, 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /movie_hub/lib/features/movies/home/presentation/notifier/trending_for_the_week_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:movie_hub/features/movies/movie_dashboard.dart'; 3 | 4 | class TrendingForTheWeekNotifier extends ChangeNotifier { 5 | final TrendingMoviesUseCase trendingMovieUsecase; 6 | 7 | TrendingForTheWeekNotifier({ 8 | required this.trendingMovieUsecase, 9 | }); 10 | 11 | int _page = 1; 12 | final List _movies = []; 13 | List? get trendingForTheWeekMovies => _movies; 14 | 15 | Future getTrendingMoviesForTheWeek({bool shouldFetch = false}) async { 16 | await _getTrendingMovies('week', shouldFetch: shouldFetch); 17 | } 18 | 19 | Future _getTrendingMovies( 20 | String timeWindow, { 21 | bool shouldFetch = false, 22 | }) async { 23 | _setPopularMovieState(TrendingForTheWeekState.isLoading); 24 | if (shouldFetch) { 25 | _page++; 26 | notifyListeners(); 27 | } 28 | 29 | final trendingMoviesResponse = await trendingMovieUsecase.call( 30 | TrendingMoviesParams(timeWindow: timeWindow, page: _page), 31 | ); 32 | 33 | trendingMoviesResponse.fold( 34 | (l) { 35 | _setPopularMovieState(TrendingForTheWeekState.isError); 36 | }, 37 | (r) { 38 | _movies.addAll(r.results ?? []); 39 | _setPopularMovieState(TrendingForTheWeekState.isDone); 40 | }, 41 | ); 42 | } 43 | 44 | TrendingForTheWeekState _trendingForTheWeekState = 45 | TrendingForTheWeekState.isDone; 46 | TrendingForTheWeekState get trendingForTheWeekState => 47 | _trendingForTheWeekState; 48 | 49 | void _setPopularMovieState(TrendingForTheWeekState state) { 50 | _trendingForTheWeekState = state; 51 | notifyListeners(); 52 | } 53 | } 54 | 55 | enum TrendingForTheWeekState { isLoading, isError, isDone } 56 | -------------------------------------------------------------------------------- /.idea/libraries/Dart_SDK.xml: -------------------------------------------------------------------------------- 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 | 28 | 29 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/data/repo-impl/profile_repo_impl.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:firebase_auth/firebase_auth.dart'; 5 | import 'package:fpdart/fpdart.dart'; 6 | import 'package:movie_hub/cores/cores.dart'; 7 | import 'package:movie_hub/features/profile/profile.dart'; 8 | 9 | class ProfileRepoImpl extends ProfileRepo { 10 | final ProfileDataSource _profileDataSource; 11 | 12 | ProfileRepoImpl({required profileDataSource}) 13 | : _profileDataSource = profileDataSource; 14 | 15 | @override 16 | Future> updateAvatar(String avatarUrl) async { 17 | return _handleAuthOperation( 18 | () => _profileDataSource.updateAvatarUrl(avatarUrl)); 19 | } 20 | 21 | @override 22 | Future>> fetchAvatars() { 23 | return _handleAuthOperation(() => _profileDataSource.getAvatars()); 24 | } 25 | 26 | @override 27 | Future> fetchProfileDetails() { 28 | return _handleAuthOperation(() => _profileDataSource.fetchProfileDetails()); 29 | } 30 | 31 | Future> _handleAuthOperation( 32 | Future Function() operation, 33 | ) async { 34 | try { 35 | final result = await operation(); 36 | return Either.right(result); 37 | } on FirebaseAuthException catch (e, s) { 38 | AppLogger.log('Error From Firebase: $e : Stack Trace $s'); 39 | return Either.left(AuthFirebaseException(e.code)); 40 | } on SocketException { 41 | return const Left(BaseFailures(message: ErrorText.noInternet)); 42 | } catch (e) { 43 | AppLogger.log(e); 44 | 45 | if (e is BaseFailures) { 46 | return Either.left(BaseFailures(message: e.message)); 47 | } 48 | 49 | return Either.left( 50 | const BaseFailures(message: 'Something went wrong, Try again!'), 51 | ); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /movie_hub/lib/features/profile/presentation/notifier/update_avatar_notifier.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fpdart/fpdart.dart'; 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/profile/profile.dart'; 5 | 6 | class UpdateAvatarNotifier extends ChangeNotifier { 7 | final UpdateAvatarUsecase _updateUsecase; 8 | 9 | UpdateAvatarNotifier({ 10 | required updateUsecase, 11 | }) : _updateUsecase = updateUsecase; 12 | 13 | Future> updateAvatar(String avatar) async { 14 | try { 15 | _setUpdateAvatarState(UpdateAvatarState.isLoading); 16 | final response = await _updateUsecase.call(avatar); 17 | return response.fold( 18 | (l) { 19 | _handleFailure(l); 20 | return Left(l); 21 | }, 22 | (r) { 23 | _handleSuccess(r); 24 | goBack(); 25 | 26 | return Right(r); 27 | }, 28 | ); 29 | } finally { 30 | _setUpdateAvatarState(UpdateAvatarState.isDone); 31 | } 32 | } 33 | 34 | UpdateAvatarState _authState = UpdateAvatarState.isDone; 35 | 36 | UpdateAvatarState get authState => _authState; 37 | 38 | void _setUpdateAvatarState(UpdateAvatarState state) { 39 | _authState = state; 40 | notifyListeners(); 41 | } 42 | 43 | void _handleFailure(Failure failure) { 44 | _setUpdateAvatarState(UpdateAvatarState.isError); 45 | 46 | SnackBarService.showErrorSnackBar( 47 | context: navigatorKey.currentContext!, 48 | message: failure.message, 49 | ); 50 | } 51 | 52 | void _handleSuccess(BaseEntity res) { 53 | _setUpdateAvatarState(UpdateAvatarState.isDone); 54 | 55 | SnackBarService.showSuccessSnackBar( 56 | context: navigatorKey.currentContext!, 57 | message: res.message, 58 | ); 59 | } 60 | } 61 | 62 | enum UpdateAvatarState { isLoading, isDone, isError } 63 | -------------------------------------------------------------------------------- /movie_hub/lib/features/auth/auth_locator.dart: -------------------------------------------------------------------------------- 1 | import 'package:get_it/get_it.dart'; 2 | import 'package:movie_hub/app/app.dart'; 3 | import 'package:movie_hub/cores/cores.dart'; 4 | import 'package:movie_hub/features/auth/auth.dart'; 5 | 6 | void setUpAuthLocator() { 7 | // final GetIt getIt = SetUpLocators.getIt; 8 | 9 | /// Data source 10 | getIt.registerLazySingleton( 11 | () => AuthDataSourceImpl( 12 | firebaseHelper: FirebaseHelper(), 13 | ), 14 | ); 15 | 16 | /// Repository 17 | getIt.registerLazySingleton( 18 | () => AuthRepoImpl( 19 | authDataSource: getIt(), 20 | ), 21 | ); 22 | 23 | /// Usecase 24 | getIt.registerLazySingleton( 25 | () => SignUpUsecase( 26 | authenticationRepository: getIt(), 27 | ), 28 | ); 29 | 30 | getIt.registerLazySingleton( 31 | () => LoginUsecase( 32 | authenticationRepository: getIt(), 33 | ), 34 | ); 35 | 36 | getIt.registerLazySingleton( 37 | () => LogOutUsecase( 38 | authenticationRepository: getIt(), 39 | ), 40 | ); 41 | 42 | getIt.registerLazySingleton( 43 | () => ForgotPasswordUsecase( 44 | authenticationRepository: getIt(), 45 | ), 46 | ); 47 | 48 | getIt.registerLazySingleton( 49 | () => CheckUserLoginStatusUsecase( 50 | authenticationRepository: getIt(), 51 | ), 52 | ); 53 | getIt.registerLazySingleton( 54 | () => AuthNotifier( 55 | forgotPasswordUsecase: getIt(), 56 | logInUsecase: getIt(), 57 | signUpUsecase: getIt(), 58 | logOutUsecase: getIt(), 59 | checkUserStatusUsecase: getIt(), 60 | ), 61 | ); 62 | } 63 | -------------------------------------------------------------------------------- /movie_hub/windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /movie_hub/windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr); 51 | std::string utf8_string; 52 | if (target_length == 0 || target_length > utf8_string.max_size()) { 53 | return utf8_string; 54 | } 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /movie_hub/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Movie Hub 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | Movie Hub 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 | io.flutter.embedded_views_preview 32 | YES 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | UIViewControllerBasedStatusBarAppearance 47 | 48 | CADisableMinimumFrameDurationOnPhone 49 | 50 | UIApplicationSupportsIndirectInputEvents 51 | 52 | 53 | 54 | --------------------------------------------------------------------------------