├── .gitattributes ├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── tmda │ │ │ │ └── MainActivity.kt │ │ ├── play_store_512.png │ │ └── res │ │ │ ├── drawable-night-v21 │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── drawable-night │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── drawable-v21 │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ └── ic_launcher.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_background.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_monochrome.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── play_store_512.png ├── res │ ├── mipmap-anydpi-v26 │ │ └── ic_launcher.xml │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_monochrome.png │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_monochrome.png │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_monochrome.png │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_monochrome.png │ └── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_monochrome.png └── settings.gradle ├── assets ├── fonts │ ├── Poppins-Black.ttf │ ├── Poppins-Bold.ttf │ ├── Poppins-ExtraBold.ttf │ ├── Poppins-ExtraLight.ttf │ ├── Poppins-Light.ttf │ ├── Poppins-Medium.ttf │ ├── Poppins-Regular.ttf │ ├── Poppins-SemiBold.ttf │ ├── Poppins-Thin.ttf │ └── SolarSystem.ttf ├── images │ ├── app_logo.png │ ├── neon_button.png │ └── play_button.svg └── lottie │ └── neon_loading.json ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings ├── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── AppIcon-20@2x.png │ │ │ ├── AppIcon-20@2x~ipad.png │ │ │ ├── AppIcon-20@3x.png │ │ │ ├── AppIcon-20~ipad.png │ │ │ ├── AppIcon-29.png │ │ │ ├── AppIcon-29@2x.png │ │ │ ├── AppIcon-29@2x~ipad.png │ │ │ ├── AppIcon-29@3x.png │ │ │ ├── AppIcon-29~ipad.png │ │ │ ├── AppIcon-40@2x.png │ │ │ ├── AppIcon-40@2x~ipad.png │ │ │ ├── AppIcon-40@3x.png │ │ │ ├── AppIcon-40~ipad.png │ │ │ ├── AppIcon-60@2x~car.png │ │ │ ├── AppIcon-60@3x~car.png │ │ │ ├── AppIcon-83.5@2x~ipad.png │ │ │ ├── AppIcon@2x.png │ │ │ ├── AppIcon@2x~ipad.png │ │ │ ├── AppIcon@3x.png │ │ │ ├── AppIcon~ios-marketing.png │ │ │ ├── AppIcon~ipad.png │ │ │ └── Contents.json │ │ ├── LaunchBackground.imageset │ │ │ ├── Contents.json │ │ │ ├── background.png │ │ │ └── darkbackground.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h └── RunnerTests │ └── RunnerTests.swift ├── lib ├── app.dart ├── bloc_observer.dart ├── config │ ├── router │ │ ├── app_router.dart │ │ └── app_router.gr.dart │ └── theme │ │ └── theme_manager.dart ├── core │ ├── animations │ │ └── custom_fade_animation.dart │ ├── api │ │ ├── api_consumer.dart │ │ ├── api_status_code.dart │ │ ├── dio_consumer.dart │ │ ├── dio_interceptor.dart │ │ └── dio_logger.dart │ ├── constants │ │ ├── api_constants.dart │ │ └── app_constants.dart │ ├── error │ │ ├── exception.dart │ │ └── failure.dart │ ├── icons │ │ └── solar_system_icons.dart │ ├── util │ │ ├── assets_manager.dart │ │ ├── color_manager.dart │ │ ├── enums.dart │ │ └── extensions.dart │ └── widgets │ │ ├── animated_indicator.dart │ │ ├── carousel_card.dart │ │ ├── cast_card.dart │ │ ├── custom_icon_button.dart │ │ ├── custom_text_form_field.dart │ │ ├── details_poster_card.dart │ │ ├── error_snack_bar.dart │ │ ├── expandable_text.dart │ │ ├── list_card.dart │ │ ├── list_card_with_save.dart │ │ ├── neon_button.dart │ │ ├── neon_light_background.dart │ │ ├── neon_light_painter.dart │ │ ├── neon_play_button.dart │ │ ├── neon_profile_picture.dart │ │ ├── no_connection.dart │ │ ├── normal_button.dart │ │ ├── poster_card.dart │ │ ├── review_card.dart │ │ ├── section_divider.dart │ │ ├── section_widget.dart │ │ ├── section_with_see_all.dart │ │ ├── tilted_image.dart │ │ └── tilted_image_with_shadow.dart ├── features │ ├── account │ │ ├── data │ │ │ ├── datasources │ │ │ │ └── account_data_source.dart │ │ │ ├── models │ │ │ │ ├── account_avatar_model.dart │ │ │ │ └── account_model.dart │ │ │ └── repositories │ │ │ │ └── account_repository_impl.dart │ │ ├── domain │ │ │ ├── entities │ │ │ │ ├── account.dart │ │ │ │ └── account_avatar.dart │ │ │ ├── repositories │ │ │ │ └── account_repository.dart │ │ │ └── usecases │ │ │ │ └── account │ │ │ │ ├── account_logout_usecase.dart │ │ │ │ └── get_account_details_usecase.dart │ │ └── presentation │ │ │ ├── bloc │ │ │ └── account_cubit │ │ │ │ ├── account_bloc.dart │ │ │ │ └── account_state.dart │ │ │ ├── components │ │ │ ├── account │ │ │ │ ├── movies_watchlist_component.dart │ │ │ │ ├── profile_component.dart │ │ │ │ └── tv_show_watchlist_component.dart │ │ │ └── see_all │ │ │ │ ├── see_all_movies_watchlist_component.dart │ │ │ │ └── see_all_tv_shows_watchlist_component.dart │ │ │ └── screen │ │ │ ├── account_screen.dart │ │ │ └── account_see_all.dart │ ├── auth │ │ ├── data │ │ │ ├── datasources │ │ │ │ └── auth_data_source.dart │ │ │ └── repositories │ │ │ │ └── auth_repository_impl.dart │ │ ├── domain │ │ │ ├── repositories │ │ │ │ └── auth_repository.dart │ │ │ └── usecases │ │ │ │ ├── user_forget_password_usecase.dart │ │ │ │ ├── user_login_usecase.dart │ │ │ │ └── user_register_usecase.dart │ │ └── presentation │ │ │ ├── cubit │ │ │ └── login_cubit │ │ │ │ ├── login_cubit.dart │ │ │ │ └── login_state.dart │ │ │ └── screens │ │ │ ├── login_screen.dart │ │ │ ├── selection_screen.dart │ │ │ └── splash_screen.dart │ ├── bottom_nav_bar │ │ └── bottom_naviagation_bar.dart │ ├── movie │ │ ├── data │ │ │ ├── datasources │ │ │ │ └── movies_data_source.dart │ │ │ ├── models │ │ │ │ ├── movie_cast_model.dart │ │ │ │ ├── movie_details_model.dart │ │ │ │ ├── movie_production_countries_model.dart │ │ │ │ ├── movie_review_model.dart │ │ │ │ ├── movie_review_owner_model.dart │ │ │ │ └── movie_video_model.dart │ │ │ └── repositories │ │ │ │ └── movies_repository_impl.dart │ │ ├── domain │ │ │ ├── entities │ │ │ │ ├── movie_cast.dart │ │ │ │ ├── movie_details.dart │ │ │ │ ├── movie_production_countries.dart │ │ │ │ ├── movie_review_owner.dart │ │ │ │ ├── movie_reviews.dart │ │ │ │ └── movie_video.dart │ │ │ ├── repositories │ │ │ │ └── movies_repository.dart │ │ │ └── usecases │ │ │ │ ├── get_movie_details_usecase.dart │ │ │ │ ├── get_new_movies_usecase.dart │ │ │ │ ├── get_now_playing_movies_usecase.dart │ │ │ │ ├── get_popular_movies_usecase.dart │ │ │ │ ├── get_recommended_movies_usecase.dart │ │ │ │ ├── get_similar_movies_usecase.dart │ │ │ │ ├── get_top_rated_movies_usecase.dart │ │ │ │ └── play_movie_video_usecase.dart │ │ └── presentation │ │ │ ├── bloc │ │ │ ├── movie_details_cubit │ │ │ │ ├── movie_details_cubit.dart │ │ │ │ └── movie_details_state.dart │ │ │ ├── movies_cubit │ │ │ │ ├── movies_cubit.dart │ │ │ │ └── movies_state.dart │ │ │ └── see_all_movies_bloc │ │ │ │ ├── see_all_movies_bloc.dart │ │ │ │ ├── see_all_movies_event.dart │ │ │ │ └── see_all_movies_state.dart │ │ │ ├── components │ │ │ ├── movie_details │ │ │ │ ├── movie_cast_component.dart │ │ │ │ ├── movie_overview_component.dart │ │ │ │ ├── movie_reviews_component.dart │ │ │ │ ├── recommended_movies_component.dart │ │ │ │ └── similar_movies_component.dart │ │ │ ├── movie_details_poster.dart │ │ │ ├── movie_main │ │ │ │ ├── new_movies_component.dart │ │ │ │ ├── now_playing_movies_component.dart │ │ │ │ ├── popular_movies_component.dart │ │ │ │ └── top_rated_movies_component.dart │ │ │ └── movie_see_all │ │ │ │ └── see_all_movies_component.dart │ │ │ └── screens │ │ │ ├── movie_details_screen.dart │ │ │ ├── movie_screen.dart │ │ │ └── see_all_movies_screen.dart │ ├── person │ │ ├── data │ │ │ ├── datasources │ │ │ │ └── person_data_source.dart │ │ │ ├── models │ │ │ │ ├── person_contents_genres_model.dart │ │ │ │ ├── person_model.dart │ │ │ │ ├── person_movie_model.dart │ │ │ │ └── person_tv_show_model.dart │ │ │ └── repositories │ │ │ │ └── person_repository_impl.dart │ │ ├── domain │ │ │ ├── entities │ │ │ │ ├── person.dart │ │ │ │ ├── person_contents_genres.dart │ │ │ │ ├── person_movie.dart │ │ │ │ └── person_tv_show.dart │ │ │ ├── repositories │ │ │ │ └── person_repository.dart │ │ │ └── usecases │ │ │ │ └── get_person_details_usecase.dart │ │ └── presentation │ │ │ ├── components │ │ │ ├── person_card.dart │ │ │ ├── person_details_component.dart │ │ │ ├── person_movies_component.dart │ │ │ └── person_tv_shows_component.dart │ │ │ ├── cubit │ │ │ ├── person_cubit.dart │ │ │ └── person_state.dart │ │ │ └── screens │ │ │ └── person_screen.dart │ ├── search │ │ ├── data │ │ │ ├── datasources │ │ │ │ └── search_data_source.dart │ │ │ ├── models │ │ │ │ ├── movie_search_model.dart │ │ │ │ ├── person_search_model.dart │ │ │ │ ├── search_genre_model.dart │ │ │ │ └── tv_show_search_model.dart │ │ │ └── repositories │ │ │ │ └── search_repository_impl.dart │ │ ├── domain │ │ │ ├── entities │ │ │ │ ├── movie_search.dart │ │ │ │ ├── person_search.dart │ │ │ │ ├── search_genre.dart │ │ │ │ └── tv_show_search.dart │ │ │ ├── repositories │ │ │ │ └── search_repository.dart │ │ │ └── usecases │ │ │ │ ├── get_search_session_id_usecase.dart │ │ │ │ ├── search_for_movie_usecase.dart │ │ │ │ ├── search_for_person_usecase.dart │ │ │ │ └── search_for_tv_show_usecase.dart │ │ └── presentation │ │ │ ├── bloc │ │ │ ├── search_bloc.dart │ │ │ ├── search_event.dart │ │ │ └── search_state.dart │ │ │ ├── components │ │ │ ├── custom_search_field.dart │ │ │ ├── movie_search_component.dart │ │ │ ├── no_search_results.dart │ │ │ ├── people_search_component.dart │ │ │ ├── person_card.dart │ │ │ ├── search_initial_body.dart │ │ │ └── tv_shows_search_component.dart │ │ │ └── screens │ │ │ └── search_screen.dart │ ├── shared │ │ ├── data │ │ │ ├── datasources │ │ │ │ ├── local_data_source.dart │ │ │ │ └── watch_list_datasource.dart │ │ │ ├── models │ │ │ │ ├── account_states_model.dart │ │ │ │ ├── auth_model.dart │ │ │ │ ├── movie_genres_model.dart │ │ │ │ ├── movies_model.dart │ │ │ │ ├── tv_show_genres_model.dart │ │ │ │ └── tv_show_model.dart │ │ │ └── repositories │ │ │ │ ├── local_repository_impl.dart │ │ │ │ └── watch_list_repository_impl.dart │ │ ├── domain │ │ │ ├── entities │ │ │ │ ├── account_states.dart │ │ │ │ ├── auth.dart │ │ │ │ ├── movie.dart │ │ │ │ ├── movie_genre.dart │ │ │ │ ├── tv_show.dart │ │ │ │ └── tv_show_genres.dart │ │ │ ├── repositories │ │ │ │ ├── local_repository.dart │ │ │ │ └── watch_list_repository.dart │ │ │ └── usecases │ │ │ │ ├── add_or_remove_movie_from_watchlist_usecase.dart │ │ │ │ ├── add_or_remove_tvshow_from_watchlist_usecase.dart │ │ │ │ ├── check_user_login_session_usecase.dart │ │ │ │ ├── get_movies_watch_list_usecase.dart │ │ │ │ ├── get_movies_watchlist_ids_set_usecase.dart │ │ │ │ ├── get_session_id_usecase.dart │ │ │ │ ├── get_tv_shows_watch_list_usecase.dart │ │ │ │ └── get_tv_shows_watchlist_ids_set_usecase.dart │ │ └── presentation │ │ │ └── blocs │ │ │ ├── auth_cubit │ │ │ ├── token_cubit.dart │ │ │ └── token_state.dart │ │ │ └── watchlist_bloc │ │ │ ├── watchlist_bloc.dart │ │ │ ├── watchlist_event.dart │ │ │ └── watchlist_state.dart │ └── tv │ │ ├── data │ │ ├── datasources │ │ │ └── tv_data_source.dart │ │ ├── models │ │ │ ├── tv_show_cast_model.dart │ │ │ ├── tv_show_details_model.dart │ │ │ ├── tv_show_network_model.dart │ │ │ ├── tv_show_production_countries_model.dart │ │ │ ├── tv_show_review_owner_model.dart │ │ │ ├── tv_show_reviews_model.dart │ │ │ └── tv_show_video_model.dart │ │ └── repositories │ │ │ └── tv_repository_impl.dart │ │ ├── domain │ │ ├── entities │ │ │ ├── tv_show_cast.dart │ │ │ ├── tv_show_details.dart │ │ │ ├── tv_show_network.dart │ │ │ ├── tv_show_production_country.dart │ │ │ ├── tv_show_review_owner.dart │ │ │ ├── tv_show_reviews.dart │ │ │ └── tv_show_video.dart │ │ ├── repositories │ │ │ └── tv_shows_repository.dart │ │ └── usecases │ │ │ ├── get_popular_tv_shows.dart │ │ │ ├── get_recommended_tv_shows_usecase.dart │ │ │ ├── get_similar_tv_shows_usecase.dart │ │ │ ├── get_top_rated_tv_shows.dart │ │ │ ├── get_tv_show_details_usecase.dart │ │ │ ├── get_tv_shows_airing_this_week_usecase.dart │ │ │ ├── get_tv_shows_airing_today.dart │ │ │ └── play_tv_show_video_usecase.dart │ │ └── presentation │ │ ├── bloc │ │ ├── see_all_tv_shows_bloc │ │ │ ├── see_all_tv_shows_bloc.dart │ │ │ ├── see_all_tv_shows_event.dart │ │ │ └── see_all_tv_shows_state.dart │ │ ├── tv_show_cubit │ │ │ ├── tv_show_cubit.dart │ │ │ └── tv_show_state.dart │ │ └── tv_show_details_cubit │ │ │ ├── tv_show_details_cubit.dart │ │ │ └── tv_show_details_state.dart │ │ ├── components │ │ ├── tv_details │ │ │ ├── episode_card.dart │ │ │ ├── recommended_tv_shows_component.dart │ │ │ ├── similar_tv_shows_component.dart │ │ │ ├── tv_details_poster.dart │ │ │ ├── tv_show_body_component.dart │ │ │ ├── tv_show_cast_component.dart │ │ │ ├── tv_show_overview_component.dart │ │ │ └── tv_show_reviews_component.dart │ │ ├── tv_see_all │ │ │ └── see_all_tv_shows_component.dart │ │ └── tv_shows │ │ │ ├── popular_tv_shows_component.dart │ │ │ ├── top_rated_tv_shows_component.dart │ │ │ ├── tv_shows_airing_this_week_component.dart │ │ │ └── tv_shows_airing_today_component.dart │ │ └── screens │ │ ├── see_all_tv_shows_screen.dart │ │ ├── tv_show_screen.dart │ │ └── tv_shows_details.dart ├── generated │ ├── intl │ │ ├── messages_all.dart │ │ └── messages_en.dart │ └── l10n.dart ├── injection_container.config.dart ├── injection_container.dart ├── l10n │ └── intl_en.arb ├── main.dart ├── register_module.dart └── route_observer.dart ├── linux ├── .gitignore ├── CMakeLists.txt ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake ├── main.cc ├── my_application.cc └── my_application.h ├── macos ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Podfile ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── 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 │ ├── Base.lproj │ │ └── MainMenu.xib │ ├── Configs │ │ ├── AppInfo.xcconfig │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── Warnings.xcconfig │ ├── DebugProfile.entitlements │ ├── Info.plist │ ├── MainFlutterWindow.swift │ └── Release.entitlements └── RunnerTests │ └── RunnerTests.swift ├── pubspec.lock ├── pubspec.yaml ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png ├── index.html └── manifest.json └── windows ├── .gitignore ├── CMakeLists.txt ├── flutter ├── CMakeLists.txt ├── generated_plugin_registrant.cc ├── generated_plugin_registrant.h └── generated_plugins.cmake └── runner ├── CMakeLists.txt ├── Runner.rc ├── flutter_window.cpp ├── flutter_window.h ├── main.cpp ├── resource.h ├── resources └── app_icon.ico ├── runner.exe.manifest ├── utils.cpp ├── utils.h ├── win32_window.cpp └── win32_window.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .build/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | .swiftpm/ 13 | migrate_working_dir/ 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 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 | 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 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | lib/core/constants/api_constants.dart 48 | -------------------------------------------------------------------------------- /.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: d3d8effc686d73e0114d71abdcccef63fa1f25d2 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: d3d8effc686d73e0114d71abdcccef63fa1f25d2 17 | base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 18 | - platform: android 19 | create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 20 | base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 21 | - platform: ios 22 | create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 23 | base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 24 | - platform: linux 25 | create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 26 | base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 27 | - platform: macos 28 | create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 29 | base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 30 | - platform: web 31 | create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 32 | base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 33 | - platform: windows 34 | create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 35 | base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | /app/.cxx 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 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | def localProperties = new Properties() 8 | def localPropertiesFile = rootProject.file('local.properties') 9 | if (localPropertiesFile.exists()) { 10 | localPropertiesFile.withReader('UTF-8') { reader -> 11 | localProperties.load(reader) 12 | } 13 | } 14 | 15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 16 | if (flutterVersionCode == null) { 17 | flutterVersionCode = '1' 18 | } 19 | 20 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 21 | if (flutterVersionName == null) { 22 | flutterVersionName = '1.0' 23 | } 24 | android { 25 | namespace "com.flutter.tmda" 26 | compileSdkVersion flutter.compileSdkVersion 27 | ndkVersion flutter.ndkVersion 28 | 29 | compileOptions { 30 | sourceCompatibility JavaVersion.VERSION_1_8 31 | targetCompatibility JavaVersion.VERSION_1_8 32 | } 33 | 34 | kotlinOptions { 35 | jvmTarget = '1.8' 36 | } 37 | 38 | sourceSets { 39 | main.java.srcDirs += 'src/main/kotlin' 40 | } 41 | 42 | defaultConfig { 43 | applicationId "com.flutter.tmda" 44 | minSdkVersion 21 45 | versionCode flutterVersionCode.toInteger() 46 | versionName flutterVersionName 47 | targetSdkVersion flutter.targetSdkVersion 48 | } 49 | 50 | buildTypes { 51 | release { 52 | signingConfig signingConfigs.debug 53 | } 54 | } 55 | } 56 | 57 | flutter { 58 | source '../..' 59 | } 60 | 61 | dependencies { 62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 63 | } 64 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/tmda/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.flutter.tmda 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/play_store_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/play_store_512.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/drawable-night-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/drawable-night/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/drawable-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/drawable/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '2.0.21' 3 | } 4 | 5 | allprojects { 6 | repositories { 7 | google() 8 | mavenCentral() 9 | } 10 | } 11 | 12 | rootProject.buildDir = "../build" 13 | 14 | subprojects { 15 | project.buildDir = "${rootProject.buildDir}/${project.name}" 16 | } 17 | 18 | subprojects { 19 | project.evaluationDependsOn(":app") 20 | } 21 | 22 | tasks.register("clean", Delete) { 23 | delete rootProject.buildDir 24 | } -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /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-8.10.2-bin.zip -------------------------------------------------------------------------------- /android/play_store_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/play_store_512.png -------------------------------------------------------------------------------- /android/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/res/mipmap-hdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-hdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/res/mipmap-mdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-mdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/res/mipmap-xhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/res/mipmap-xxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/res/mipmap-xxxhdpi/ic_launcher_monochrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/android/res/mipmap-xxxhdpi/ic_launcher_monochrome.png -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | } 9 | settings.ext.flutterSdkPath = flutterSdkPath() 10 | 11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | google() 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | } 19 | 20 | plugins { 21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 22 | id "com.android.application" version "8.2.1" apply false 23 | id "org.jetbrains.kotlin.android" version "2.0.21" apply false 24 | } 25 | 26 | include ":app" 27 | -------------------------------------------------------------------------------- /assets/fonts/Poppins-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/fonts/Poppins-Black.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/fonts/Poppins-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/fonts/Poppins-ExtraBold.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/fonts/Poppins-ExtraLight.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/fonts/Poppins-Light.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/fonts/Poppins-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/fonts/Poppins-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/fonts/Poppins-SemiBold.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/fonts/Poppins-Thin.ttf -------------------------------------------------------------------------------- /assets/fonts/SolarSystem.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/fonts/SolarSystem.ttf -------------------------------------------------------------------------------- /assets/images/app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/images/app_logo.png -------------------------------------------------------------------------------- /assets/images/neon_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/assets/images/neon_button.png -------------------------------------------------------------------------------- /assets/images/play_button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '14.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 | 33 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 34 | target 'RunnerTests' do 35 | inherit! :search_paths 36 | end 37 | end 38 | 39 | post_install do |installer| 40 | installer.pods_project.targets.each do |target| 41 | flutter_additional_ios_build_settings(target) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - flutter_secure_storage (6.0.0): 4 | - Flutter 5 | - path_provider_foundation (0.0.1): 6 | - Flutter 7 | - FlutterMacOS 8 | - sqflite_darwin (0.0.4): 9 | - Flutter 10 | - FlutterMacOS 11 | - url_launcher_ios (0.0.1): 12 | - Flutter 13 | 14 | DEPENDENCIES: 15 | - Flutter (from `Flutter`) 16 | - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) 17 | - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) 18 | - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) 19 | - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) 20 | 21 | EXTERNAL SOURCES: 22 | Flutter: 23 | :path: Flutter 24 | flutter_secure_storage: 25 | :path: ".symlinks/plugins/flutter_secure_storage/ios" 26 | path_provider_foundation: 27 | :path: ".symlinks/plugins/path_provider_foundation/darwin" 28 | sqflite_darwin: 29 | :path: ".symlinks/plugins/sqflite_darwin/darwin" 30 | url_launcher_ios: 31 | :path: ".symlinks/plugins/url_launcher_ios/ios" 32 | 33 | SPEC CHECKSUMS: 34 | Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 35 | flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13 36 | path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 37 | sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 38 | url_launcher_ios: 694010445543906933d732453a59da0a173ae33d 39 | 40 | PODFILE CHECKSUM: e30f02f9d1c72c47bb6344a0a748c9d268180865 41 | 42 | COCOAPODS: 1.16.2 43 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 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 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x~ipad.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20~ipad.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x~ipad.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29~ipad.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x~ipad.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40~ipad.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x~car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x~car.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@3x~car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@3x~car.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5@2x~ipad.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x~ipad.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon~ios-marketing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon~ios-marketing.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "background.png", 5 | "idiom" : "universal" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "filename" : "darkbackground.png", 15 | "idiom" : "universal" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "LaunchImage.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "LaunchImage@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "LaunchImage@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /lib/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_localizations/flutter_localizations.dart'; 4 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 5 | import 'package:tmda/config/router/app_router.dart'; 6 | import 'package:tmda/config/theme/theme_manager.dart'; 7 | import 'package:tmda/core/util/extensions.dart'; 8 | import 'package:tmda/injection_container.dart'; 9 | import 'package:tmda/route_observer.dart'; 10 | 11 | import 'generated/l10n.dart'; 12 | 13 | class TmdaApp extends StatefulWidget { 14 | static late S tr; 15 | static late BuildContext mainContext; 16 | const TmdaApp({super.key}); 17 | 18 | @override 19 | State createState() => _TmdaAppState(); 20 | } 21 | 22 | class _TmdaAppState extends State { 23 | @override 24 | Widget build(BuildContext context) { 25 | return ScreenUtilInit( 26 | designSize: const Size(360, 800), 27 | minTextAdapt: true, 28 | splitScreenMode: true, 29 | builder: (context, child) => MaterialApp.router( 30 | debugShowCheckedModeBanner: false, 31 | routerConfig: getIt().config( 32 | navigatorObservers: () => [MyRouteObserver(), AutoRouteObserver()], 33 | ), 34 | localizationsDelegates: const [ 35 | S.delegate, 36 | GlobalMaterialLocalizations.delegate, 37 | GlobalWidgetsLocalizations.delegate, 38 | GlobalCupertinoLocalizations.delegate, 39 | ], 40 | onGenerateTitle: (context) { 41 | TmdaApp.tr = context.tr; 42 | return TmdaApp.tr.appName; 43 | }, 44 | locale: Locale("en"), 45 | theme: ThemeManager.defaultTheme(), 46 | ), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/bloc_observer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | 4 | class MyBlocObserver extends BlocObserver { 5 | @override 6 | void onCreate(BlocBase bloc) { 7 | super.onCreate(bloc); 8 | if(kDebugMode){ 9 | print('onCreate -- ${bloc.runtimeType}'); 10 | } 11 | } 12 | 13 | @override 14 | void onChange(BlocBase bloc, Change change) { 15 | super.onChange(bloc, change); 16 | if(kDebugMode){ 17 | print('onChange -- ${bloc.runtimeType}, $change'); 18 | } 19 | } 20 | 21 | @override 22 | void onError(BlocBase bloc, Object error, StackTrace stackTrace) { 23 | if(kDebugMode){ 24 | print('onError -- ${bloc.runtimeType}, $error'); 25 | } 26 | super.onError(bloc, error, stackTrace); 27 | } 28 | 29 | @override 30 | void onClose(BlocBase bloc) { 31 | super.onClose(bloc); 32 | if(kDebugMode){ 33 | print('onClose -- ${bloc.runtimeType}'); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /lib/core/animations/custom_fade_animation.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CustomFadeAnimation extends StatefulWidget { 4 | final Widget child; 5 | final Duration duration; 6 | 7 | const CustomFadeAnimation({ 8 | super.key, 9 | required this.child, 10 | this.duration = const Duration(milliseconds: 250), 11 | }); 12 | 13 | @override 14 | State createState() => _CustomFadeAnimationState(); 15 | } 16 | 17 | class _CustomFadeAnimationState extends State 18 | with TickerProviderStateMixin { 19 | late AnimationController _controller; 20 | late Animation _fadeAnimation; 21 | 22 | @override 23 | void initState() { 24 | super.initState(); 25 | 26 | _controller = AnimationController( 27 | vsync: this, 28 | duration: widget.duration, 29 | ); 30 | 31 | _fadeAnimation = Tween( 32 | begin: 0.0, 33 | end: 1.0, 34 | ).animate(CurvedAnimation( 35 | parent: _controller, 36 | curve: Curves.easeInOut, 37 | )); 38 | 39 | _controller.forward(); 40 | } 41 | 42 | @override 43 | void dispose() { 44 | _controller.dispose(); 45 | super.dispose(); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return FadeTransition( 51 | opacity: _fadeAnimation, 52 | child: widget.child, 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/core/api/api_consumer.dart: -------------------------------------------------------------------------------- 1 | abstract class ApiConsumer { 2 | Future get( 3 | String endPointPath, { 4 | Map? queryParameters, 5 | }); 6 | Future post( 7 | String endPointPath, { 8 | Map? body, 9 | Map? queryParameters, 10 | }); 11 | Future put( 12 | String endPointPath, { 13 | Map? body, 14 | Map? queryParameters, 15 | }); 16 | Future delete( 17 | String endPointPath, { 18 | Map? body, 19 | Map? queryParameters, 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /lib/core/api/api_status_code.dart: -------------------------------------------------------------------------------- 1 | class ApiStatusCodes{ 2 | static const int ok = 200; 3 | static const int badRequest = 400; 4 | static const int unauthorized = 401; 5 | static const int forbidden = 403; 6 | static const int notFound = 404; 7 | static const int conflict = 409; 8 | static const int internalServerError = 500; 9 | } -------------------------------------------------------------------------------- /lib/core/api/dio_logger.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @lazySingleton 5 | class DioLogInterceptor extends LogInterceptor{ 6 | @override 7 | bool get request => true; 8 | @override 9 | bool get requestBody => true; 10 | @override 11 | bool get requestHeader => true; 12 | @override 13 | bool get responseBody => true; 14 | } -------------------------------------------------------------------------------- /lib/core/constants/app_constants.dart: -------------------------------------------------------------------------------- 1 | class AppConstants{ 2 | static const int cacheDuration = 7; 3 | static const String cacheFolder = 'Tmda'; 4 | } -------------------------------------------------------------------------------- /lib/core/error/failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class Failure extends Equatable{ 4 | final String message; 5 | 6 | const Failure(this.message); 7 | @override 8 | List get props => [message]; 9 | } 10 | 11 | class CacheFailure extends Failure{ 12 | const CacheFailure(super.message); 13 | } 14 | 15 | class ApiFailure extends Failure{ 16 | const ApiFailure(super.message); 17 | } -------------------------------------------------------------------------------- /lib/core/util/assets_manager.dart: -------------------------------------------------------------------------------- 1 | class AssetsManager { 2 | // Fonts Assets 3 | static const fontFamily = 'Poppins'; 4 | 5 | // Image Assets 6 | static const appLogo = 'assets/images/app_logo.png'; 7 | static const neonButton = 'assets/images/neon_button.png'; 8 | static const neonPlayButton = 'assets/images/play_button.svg'; 9 | static const neonLoading = 'assets/lottie/neon_loading.json'; 10 | static const neonAvatar = 'https://i.imgur.com/5fSzEvQ.jpg'; 11 | static const errorPoster = 'https://i.imgur.com/NUkCTEs.jpg'; 12 | } 13 | -------------------------------------------------------------------------------- /lib/core/util/color_manager.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ColorsManager{ 4 | static const Color primaryColor = Color(0xFF00FFFF); 5 | static const Color secondaryColor = Color(0xFFFE53BB); 6 | static const Color backgroundColor = Color(0xFF000000); 7 | static const Color inActiveColor = Color(0xFFB1AEAE); 8 | static const Color ratingIconColor = Color(0xFFD1BC00); 9 | static const Color errorColor = Color(0xFFDA0A0A); 10 | static const Color darkPrimary = Color(0xFF007373); 11 | static const Color bottomNavigationColor = Color(0xFF343434); 12 | static const Color reviewCardColor = Color(0xFF343434); 13 | } -------------------------------------------------------------------------------- /lib/core/util/enums.dart: -------------------------------------------------------------------------------- 1 | enum MovieType { 2 | newMovies('New Movies'), 3 | popularMovies('Popular Movies'), 4 | topRatedMovies('Top Rated Movies'), 5 | recommendedMovies('Recommended Movies'), 6 | similarMovies('Similar Movies'); 7 | 8 | const MovieType(this.name); 9 | final String name; 10 | } 11 | 12 | enum TvShowType { 13 | topRatedTvShows('Top Rated Shows'), 14 | airingToday('Airing Today'), 15 | popularTvShows('Popular Shows'), 16 | recommendedTvShows('Recommended Shows'), 17 | similarTvShows('Similar Shows'); 18 | const TvShowType(this.name); 19 | final String name; 20 | } 21 | 22 | enum WatchListType { 23 | moviesWatchList('Movies Watchlist'), 24 | tvShowWatchList('TvShows Watchlist'); 25 | const WatchListType(this.name); 26 | final String name; 27 | } 28 | 29 | enum PersonScreenType { 30 | withAllContent(), 31 | withMovies(), 32 | withTvShows() 33 | } 34 | 35 | enum PersonSeeAllType { 36 | moviesList('Movies'), 37 | tvShowsList('TvShows'); 38 | const PersonSeeAllType(this.name); 39 | final String name; 40 | } 41 | 42 | enum BlocState { 43 | initial, 44 | loading, 45 | success, 46 | failure, 47 | } 48 | 49 | enum UserAccountState { 50 | loggedIn, 51 | loggedOut, 52 | fail, 53 | } -------------------------------------------------------------------------------- /lib/core/util/extensions.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:intl/intl.dart' as localization; 3 | import 'package:tmda/generated/l10n.dart'; 4 | 5 | extension BuildContextExtension on BuildContext { 6 | TextTheme get textTheme => Theme.of(this).textTheme; 7 | 8 | ColorScheme get colorScheme => Theme.of(this).colorScheme; 9 | 10 | double get screenWidth => MediaQuery.sizeOf(this).width; 11 | 12 | double get screenHeight => MediaQuery.sizeOf(this).height; 13 | 14 | S get tr => S.of(this); 15 | 16 | bool get isEnglishLanguage => localization.Intl.getCurrentLocale() == 'en'; 17 | 18 | bool get hasFocus => FocusScope.of(this).hasPrimaryFocus; 19 | 20 | bool get isKeyboardClosed => MediaQuery.of(this).viewInsets.bottom <= 0; 21 | 22 | bool get isDarkTheme => Theme.of(this).brightness == Brightness.dark; 23 | } 24 | -------------------------------------------------------------------------------- /lib/core/widgets/animated_indicator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | 4 | class AnimatedIndicator extends StatelessWidget { 5 | final int currentIndex; 6 | final int dotsCount; 7 | final Axis axisDirection; 8 | final Color selectedColor; 9 | final Color unSelectedColor; 10 | final double dotWidth; 11 | final double dotHeight; 12 | final double selectedDotWidth; 13 | 14 | const AnimatedIndicator({ 15 | super.key, 16 | required this.currentIndex, 17 | required this.dotsCount, 18 | required this.axisDirection, 19 | required this.selectedColor, 20 | required this.unSelectedColor, 21 | required this.dotWidth, 22 | required this.dotHeight, 23 | required this.selectedDotWidth, 24 | }); 25 | 26 | 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return Row( 31 | mainAxisAlignment: MainAxisAlignment.center, 32 | children: List.generate( 33 | dotsCount, 34 | (index) => Padding( 35 | padding: const EdgeInsets.symmetric(horizontal: 5.0).r, 36 | child: AnimatedContainer( 37 | curve: Curves.easeIn, 38 | duration: const Duration(milliseconds: 300), 39 | width: index == currentIndex ? selectedDotWidth : dotWidth, 40 | height: dotHeight, 41 | decoration: BoxDecoration( 42 | color: index == currentIndex ? selectedColor : unSelectedColor, 43 | borderRadius: BorderRadius.circular(20).w, 44 | ), 45 | ), 46 | ), 47 | ), 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/core/widgets/cast_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:tmda/core/util/extensions.dart'; 4 | import 'package:tmda/core/widgets/tilted_image_with_shadow.dart'; 5 | 6 | class CastCard extends StatelessWidget { 7 | const CastCard({ 8 | super.key, 9 | required this.actorPicPath, 10 | required this.actorName, 11 | required this.actorCharacterName, 12 | required this.onTap, 13 | required this.errorImagePath, 14 | }); 15 | 16 | final String actorPicPath; 17 | final String actorName; 18 | final String actorCharacterName; 19 | final String errorImagePath; 20 | final void Function() onTap; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return GestureDetector( 25 | onTap: onTap, 26 | child: Stack( 27 | fit: StackFit.passthrough, 28 | children: [ 29 | TiltedImageWithShadow( 30 | errorImagePath: errorImagePath, 31 | imagePath: actorPicPath, 32 | width: 130.w, 33 | height: 220.h, 34 | ), 35 | Positioned( 36 | left: 5.w, 37 | right: 20.w, 38 | bottom: 20.h, 39 | child: Text( 40 | actorName, 41 | overflow: TextOverflow.ellipsis, 42 | style: context.textTheme.bodySmall, 43 | ), 44 | ), 45 | Positioned( 46 | left: 5.w, 47 | right: 15.w, 48 | bottom: 5.h, 49 | child: Text( 50 | actorCharacterName, 51 | overflow: TextOverflow.ellipsis, 52 | style: context.textTheme.bodySmall, 53 | ), 54 | ) 55 | ], 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/core/widgets/custom_icon_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | 4 | class CustomIconButton extends StatelessWidget { 5 | const CustomIconButton({ 6 | super.key, 7 | required this.onPressed, 8 | required this.icon, 9 | }); 10 | final void Function() onPressed; 11 | final IconData icon; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Container( 16 | height: 40.h, 17 | width: 40.w, 18 | decoration: BoxDecoration( 19 | color: Colors.black.withValues(alpha: 0.4), 20 | borderRadius: BorderRadius.all(const Radius.circular(10).w), 21 | ), 22 | child: IconButton( 23 | onPressed: onPressed, 24 | icon: Icon( 25 | icon, 26 | color: Colors.white, 27 | size: 20.sp, 28 | ), 29 | ), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/core/widgets/error_snack_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:tmda/core/animations/custom_fade_animation.dart'; 4 | import 'package:tmda/core/icons/solar_system_icons.dart'; 5 | import 'package:tmda/core/util/color_manager.dart'; 6 | import 'package:tmda/core/util/extensions.dart'; 7 | 8 | SnackBar errorSnackBar({ 9 | required String errorMessage, 10 | required BuildContext context, 11 | }) { 12 | return SnackBar( 13 | animation: CurvedAnimation( 14 | curve: Curves.bounceIn, 15 | parent: kAlwaysCompleteAnimation, 16 | ), 17 | behavior: SnackBarBehavior.floating, 18 | content: CustomFadeAnimation( 19 | child: Row( 20 | children: [ 21 | Icon( 22 | SolarSystemIcons.error, 23 | color: ColorsManager.errorColor, 24 | size: 20.sp, 25 | ), 26 | SizedBox(width: 3.w), 27 | Text( 28 | errorMessage, 29 | style: context.textTheme.bodySmall!.copyWith(color: Colors.white), 30 | ), 31 | ], 32 | ), 33 | ), 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /lib/core/widgets/neon_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:tmda/core/util/assets_manager.dart'; 4 | 5 | class NeonButton extends StatelessWidget { 6 | const NeonButton({ 7 | super.key, 8 | required this.onTap, 9 | required this.child, 10 | }); 11 | 12 | final void Function() onTap; 13 | final Widget child; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return InkWell( 18 | onTap: onTap, 19 | child: SizedBox( 20 | width: 150.w, 21 | height: 48.h, 22 | child: Stack( 23 | children: [ 24 | SizedBox.expand( 25 | child: Image.asset( 26 | AssetsManager.neonButton, 27 | fit: BoxFit.fill, 28 | ), 29 | ), 30 | Center( 31 | child: child, 32 | ) 33 | ], 34 | ), 35 | ), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/core/widgets/neon_light_painter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 | 5 | class NeonLightPainter extends StatelessWidget { 6 | const NeonLightPainter({ 7 | super.key, 8 | required this.color, 9 | }); 10 | 11 | final Color color; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return ImageFiltered( 16 | imageFilter: ImageFilter.blur( 17 | sigmaX: 50, 18 | sigmaY: 50, 19 | tileMode: TileMode.decal, 20 | ), 21 | child: Container( 22 | width: 150.w, 23 | height: 150.h, 24 | decoration: BoxDecoration( 25 | shape: BoxShape.circle, 26 | color: color, 27 | ), 28 | ), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/core/widgets/neon_play_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:flutter_svg/flutter_svg.dart'; 4 | import 'package:tmda/core/util/assets_manager.dart'; 5 | 6 | class NeonPlayButton extends StatelessWidget { 7 | const NeonPlayButton({ 8 | super.key, 9 | required this.onTap, 10 | }); 11 | final void Function() onTap; 12 | @override 13 | Widget build(BuildContext context) { 14 | return GestureDetector( 15 | onTap: onTap, 16 | child: SvgPicture.asset( 17 | AssetsManager.neonPlayButton, 18 | width: 50.w, 19 | height: 50.h, 20 | ), 21 | ); 22 | } 23 | } -------------------------------------------------------------------------------- /lib/core/widgets/no_connection.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:tmda/core/icons/solar_system_icons.dart'; 4 | import 'package:tmda/core/util/color_manager.dart'; 5 | import 'package:tmda/core/util/extensions.dart'; 6 | import 'package:tmda/core/widgets/normal_button.dart'; 7 | 8 | class NoConnection extends StatelessWidget { 9 | const NoConnection({ 10 | super.key, 11 | required this.onTap, 12 | }); 13 | final void Function() onTap; 14 | @override 15 | Widget build(BuildContext context) { 16 | return Center( 17 | child: Column( 18 | mainAxisAlignment: MainAxisAlignment.center, 19 | children: [ 20 | Icon( 21 | SolarSystemIcons.wifi, 22 | color: ColorsManager.primaryColor, 23 | size: 100.sp, 24 | ), 25 | SizedBox(height: 30.h), 26 | Text( 27 | context.tr.error, 28 | style: context.textTheme.titleLarge! 29 | .copyWith(color: ColorsManager.primaryColor), 30 | ), 31 | Text( 32 | context.tr.checkYourConnection, 33 | style: context.textTheme.titleSmall! 34 | .copyWith(fontSize: 18.sp, color: ColorsManager.darkPrimary), 35 | ), 36 | SizedBox(height: 40.h), 37 | NormalButton( 38 | onTap: onTap, 39 | width: 180.w, 40 | height: 48.h, 41 | child: Text( 42 | context.tr.tryAgain, 43 | style: context.textTheme.titleSmall! 44 | .copyWith(fontWeight: FontWeight.w500), 45 | ), 46 | ) 47 | ], 48 | ), 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/core/widgets/normal_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:tmda/core/util/color_manager.dart'; 4 | 5 | class NormalButton extends StatelessWidget { 6 | const NormalButton({ 7 | super.key, 8 | required this.onTap, 9 | required this.child, 10 | required this.width, 11 | required this.height 12 | }); 13 | final void Function() onTap; 14 | final Widget child; 15 | final double width; 16 | final double height; 17 | @override 18 | Widget build(BuildContext context) { 19 | return InkWell( 20 | onTap: onTap, 21 | child: Container( 22 | width: width, 23 | height: height, 24 | decoration: BoxDecoration( 25 | color: ColorsManager.darkPrimary, 26 | borderRadius: BorderRadius.circular(10).r, 27 | ), 28 | child: Center( 29 | child: child, 30 | ), 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/core/widgets/section_divider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:tmda/core/util/color_manager.dart'; 4 | 5 | class SectionDivider extends StatelessWidget { 6 | const SectionDivider({ 7 | super.key, 8 | }); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Padding( 13 | padding: const EdgeInsets.all(4.0).r, 14 | child: const Divider( 15 | color: ColorsManager.inActiveColor, 16 | thickness: 1, 17 | indent: 20, 18 | endIndent: 30, 19 | ), 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/core/widgets/section_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:tmda/core/util/extensions.dart'; 4 | 5 | class SectionWidget extends StatelessWidget { 6 | const SectionWidget({ 7 | super.key, 8 | required this.title, 9 | required this.color, 10 | }); 11 | final String title; 12 | final Color color; 13 | @override 14 | Widget build(BuildContext context) { 15 | return Padding( 16 | padding: const EdgeInsets.only(left: 22, top: 16, bottom: 16).r, 17 | child: Row( 18 | children: [ 19 | Container( 20 | height: 23.h, 21 | width: 5.h, 22 | decoration: BoxDecoration( 23 | color: color, 24 | borderRadius: BorderRadius.all(const Radius.circular(10)).r, 25 | ), 26 | ), 27 | SizedBox(width: 8.w), 28 | Text( 29 | title, 30 | style: context.textTheme.titleMedium, 31 | ), 32 | ], 33 | ), 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/core/widgets/tilted_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_cache_manager/flutter_cache_manager.dart'; 4 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 5 | import 'package:tmda/core/constants/api_constants.dart'; 6 | import 'package:tmda/core/constants/app_constants.dart'; 7 | 8 | class TiltedImage extends StatelessWidget { 9 | const TiltedImage({ 10 | super.key, 11 | required this.imagePath, 12 | required this.width, 13 | required this.height, 14 | required this.errorImagePath, 15 | }); 16 | 17 | final String imagePath; 18 | final double width; 19 | final double height; 20 | final String errorImagePath; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Transform( 25 | transform: Matrix4.skewX(-0.05), 26 | child: ClipRRect( 27 | borderRadius: const BorderRadius.all(Radius.circular(20)).r, 28 | child: CachedNetworkImage( 29 | width: width, 30 | height: height, 31 | imageUrl: imagePath.isNotEmpty 32 | ? ApiConstants.imageUrl(imagePath) 33 | : errorImagePath, 34 | fit: BoxFit.cover, 35 | cacheManager: CacheManager( 36 | Config( 37 | AppConstants.cacheFolder, 38 | stalePeriod: const Duration(days: AppConstants.cacheDuration), 39 | ) 40 | ), 41 | ), 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/core/widgets/tilted_image_with_shadow.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_cache_manager/flutter_cache_manager.dart'; 4 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 5 | import 'package:tmda/core/constants/api_constants.dart'; 6 | import 'package:tmda/core/constants/app_constants.dart'; 7 | 8 | class TiltedImageWithShadow extends StatelessWidget { 9 | const TiltedImageWithShadow({ 10 | super.key, 11 | required this.imagePath, 12 | required this.width, 13 | required this.height, 14 | required this.errorImagePath, 15 | }); 16 | 17 | final String imagePath; 18 | final double width; 19 | final double height; 20 | final String errorImagePath; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Transform( 25 | transform: Matrix4.skewX(-0.05), 26 | child: ClipRRect( 27 | borderRadius: const BorderRadius.all(Radius.circular(20)).r, 28 | child: ImageFiltered( 29 | imageFilter: ColorFilter.mode( 30 | Colors.black.withValues(alpha: 0.3), 31 | BlendMode.darken, 32 | ), 33 | child: CachedNetworkImage( 34 | width: width, 35 | height: height, 36 | imageUrl: imagePath.isNotEmpty 37 | ? ApiConstants.imageUrl(imagePath) 38 | : errorImagePath, 39 | fit: BoxFit.cover, 40 | cacheManager: CacheManager(Config( 41 | AppConstants.cacheFolder, 42 | stalePeriod: const Duration(days: AppConstants.cacheDuration), 43 | )), 44 | ), 45 | ), 46 | ), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/features/account/data/datasources/account_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:injectable/injectable.dart'; 2 | import 'package:tmda/core/api/api_consumer.dart'; 3 | import 'package:tmda/core/constants/api_constants.dart'; 4 | import 'package:tmda/core/error/exception.dart'; 5 | import 'package:tmda/features/account/data/models/account_model.dart'; 6 | 7 | abstract class AccountDataSource { 8 | Future getAccountDetails(); 9 | Future accountLogOut({required String sessionId}); 10 | } 11 | 12 | @LazySingleton(as: AccountDataSource) 13 | class AccountDataSourceImpl extends AccountDataSource { 14 | final ApiConsumer _apiConsumer; 15 | AccountDataSourceImpl(this._apiConsumer); 16 | 17 | @override 18 | Future getAccountDetails() async { 19 | final accountDetails = await _apiConsumer.get(ApiConstants.accountEndPoint); 20 | return AccountModel.fromJson(accountDetails); 21 | } 22 | 23 | @override 24 | Future accountLogOut({required String sessionId}) async { 25 | final response = await _apiConsumer.delete( 26 | ApiConstants.accountLogoutEndPoint, 27 | body: {'session_id': sessionId}, 28 | ); 29 | if (response['success'] == false) { 30 | throw ServerException('${response['status_message']}'); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/features/account/data/models/account_avatar_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/account/domain/entities/account_avatar.dart'; 2 | 3 | class AccountAvatarModel extends AccountAvatar{ 4 | const AccountAvatarModel({required super.path}); 5 | 6 | factory AccountAvatarModel.fromJson(Map jsonData){ 7 | return AccountAvatarModel(path: jsonData['avatar_path'] ?? ''); 8 | } 9 | } -------------------------------------------------------------------------------- /lib/features/account/data/models/account_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/account/data/models/account_avatar_model.dart'; 2 | import 'package:tmda/features/account/domain/entities/account.dart'; 3 | 4 | class AccountModel extends Account { 5 | const AccountModel({ 6 | required super.username, 7 | required super.id, 8 | required super.accountAvatar, 9 | required super.name, 10 | }); 11 | 12 | factory AccountModel.fromJson(Map jsonData) { 13 | return AccountModel( 14 | username: jsonData['username'], 15 | id: jsonData['id'], 16 | accountAvatar: AccountAvatarModel.fromJson(jsonData['avatar']['tmdb']), 17 | name: jsonData['name'] ?? '', 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/account/data/repositories/account_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/exception.dart'; 4 | import 'package:tmda/core/error/failure.dart'; 5 | import 'package:tmda/features/shared/data/datasources/local_data_source.dart'; 6 | import 'package:tmda/features/account/data/datasources/account_data_source.dart'; 7 | import 'package:tmda/features/account/data/models/account_model.dart'; 8 | import 'package:tmda/features/account/domain/repositories/account_repository.dart'; 9 | 10 | @LazySingleton(as: AccountRepository) 11 | class AccountRepositoryImpl extends AccountRepository{ 12 | final AccountDataSource _accountDataSource; 13 | final LocalDataSource _localDataSource; 14 | 15 | AccountRepositoryImpl(this._accountDataSource, this._localDataSource); 16 | 17 | 18 | 19 | @override 20 | Future> getAccountDetails() async{ 21 | try{ 22 | final result = await _accountDataSource.getAccountDetails(); 23 | return right(result); 24 | }on ServerException catch(exception){ 25 | return left(Failure(exception.message!)); 26 | } 27 | } 28 | 29 | 30 | @override 31 | Future> accountLogOut({required String sessionId}) async{ 32 | try{ 33 | final result = await _accountDataSource.accountLogOut(sessionId: sessionId); 34 | _localDataSource.deleteSessionId(); 35 | return right(result); 36 | }on ServerException catch(exception){ 37 | return left(Failure(exception.message!)); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /lib/features/account/domain/entities/account.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tmda/features/account/domain/entities/account_avatar.dart'; 3 | 4 | class Account extends Equatable { 5 | final String name; 6 | final String username; 7 | final int id; 8 | final AccountAvatar accountAvatar; 9 | 10 | const Account({ 11 | required this.name, 12 | required this.username, 13 | required this.id, 14 | required this.accountAvatar, 15 | }); 16 | 17 | @override 18 | List get props => [ 19 | name, 20 | username, 21 | accountAvatar, 22 | id, 23 | ]; 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/account/domain/entities/account_avatar.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class AccountAvatar extends Equatable{ 4 | final String path; 5 | const AccountAvatar({required this.path}); 6 | 7 | 8 | @override 9 | List get props => [path]; 10 | } -------------------------------------------------------------------------------- /lib/features/account/domain/repositories/account_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:tmda/core/error/failure.dart'; 3 | import 'package:tmda/features/account/domain/entities/account.dart'; 4 | 5 | abstract class AccountRepository { 6 | Future> getAccountDetails(); 7 | Future> accountLogOut({required String sessionId}); 8 | } -------------------------------------------------------------------------------- /lib/features/account/domain/usecases/account/account_logout_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/account/domain/repositories/account_repository.dart'; 5 | 6 | @lazySingleton 7 | class AccountLogoutUseCase{ 8 | final AccountRepository _accountRepository; 9 | const AccountLogoutUseCase(this._accountRepository); 10 | Future> call({required String sessionId}) async{ 11 | return await _accountRepository.accountLogOut(sessionId: sessionId); 12 | } 13 | } -------------------------------------------------------------------------------- /lib/features/account/domain/usecases/account/get_account_details_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/account/domain/entities/account.dart'; 5 | import 'package:tmda/features/account/domain/repositories/account_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetAccountDetailsUseCase{ 9 | final AccountRepository _accountRepository; 10 | const GetAccountDetailsUseCase(this._accountRepository); 11 | 12 | Future> call() async{ 13 | return await _accountRepository.getAccountDetails(); 14 | } 15 | } -------------------------------------------------------------------------------- /lib/features/account/presentation/bloc/account_cubit/account_state.dart: -------------------------------------------------------------------------------- 1 | part of 'account_bloc.dart'; 2 | 3 | class AccountState extends Equatable { 4 | final Account account; 5 | final BlocState accountTabState; 6 | final String accountFailMessage; 7 | final UserAccountState userAccountState; 8 | const AccountState({ 9 | this.account = const Account( 10 | accountAvatar: AccountAvatar(path: ''), 11 | id: 0, 12 | username: '', 13 | name: '', 14 | ), 15 | this.accountTabState = BlocState.loading, 16 | this.accountFailMessage = '', 17 | this.userAccountState = UserAccountState.loggedIn, 18 | }); 19 | 20 | AccountState copyWith({ 21 | Account? account, 22 | BlocState? accountTabState, 23 | String? accountFailMessage, 24 | UserAccountState? userAccountState, 25 | }) { 26 | return AccountState( 27 | account: account ?? this.account, 28 | accountTabState: accountTabState ?? this.accountTabState, 29 | accountFailMessage: accountFailMessage ?? this.accountFailMessage, 30 | userAccountState: userAccountState ?? this.userAccountState, 31 | ); 32 | } 33 | 34 | @override 35 | List get props => [ 36 | account, 37 | accountTabState, 38 | accountFailMessage, 39 | userAccountState, 40 | ]; 41 | } 42 | -------------------------------------------------------------------------------- /lib/features/auth/domain/repositories/auth_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:tmda/core/error/failure.dart'; 3 | import 'package:tmda/features/shared/domain/entities/auth.dart'; 4 | 5 | abstract class AuthRepository { 6 | Future> userLogin(String username, String password); 7 | Future> userRegister(); 8 | Future> userForgetPassword(); 9 | } 10 | -------------------------------------------------------------------------------- /lib/features/auth/domain/usecases/user_forget_password_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/auth/domain/repositories/auth_repository.dart'; 5 | 6 | @lazySingleton 7 | class UserForgetPasswordUseCase { 8 | final AuthRepository _authRepository; 9 | const UserForgetPasswordUseCase(this._authRepository); 10 | Future> call() async { 11 | return await _authRepository.userForgetPassword(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/auth/domain/usecases/user_login_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/auth.dart'; 5 | import 'package:tmda/features/auth/domain/repositories/auth_repository.dart'; 6 | 7 | @lazySingleton 8 | class UserLoginUseCase { 9 | final AuthRepository _authRepository; 10 | const UserLoginUseCase(this._authRepository); 11 | 12 | Future> call(String username, String password) async{ 13 | return await _authRepository.userLogin(username, password); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/auth/domain/usecases/user_register_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/auth/domain/repositories/auth_repository.dart'; 5 | 6 | @lazySingleton 7 | class UserRegisterUseCase { 8 | final AuthRepository _authRepository; 9 | const UserRegisterUseCase(this._authRepository); 10 | Future> call() async { 11 | return await _authRepository.userRegister(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/cubit/login_cubit/login_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | import 'package:tmda/features/auth/domain/usecases/user_forget_password_usecase.dart'; 5 | import 'package:tmda/features/auth/domain/usecases/user_login_usecase.dart'; 6 | import 'package:tmda/features/auth/domain/usecases/user_register_usecase.dart'; 7 | import 'package:tmda/features/shared/domain/entities/auth.dart'; 8 | 9 | part 'login_state.dart'; 10 | 11 | @injectable 12 | class LoginCubit extends Cubit { 13 | UserRegisterUseCase userRegisterUseCase; 14 | UserForgetPasswordUseCase userForgetPasswordUseCase; 15 | UserLoginUseCase userLoginUseCase; 16 | LoginCubit({ 17 | required this.userRegisterUseCase, 18 | required this.userForgetPasswordUseCase, 19 | required this.userLoginUseCase, 20 | }) : super(LoginInitial()); 21 | 22 | Future userLogin(String username, String password) async { 23 | emit(LoginLoadingState()); 24 | final response = await userLoginUseCase(username, password); 25 | response.fold( 26 | (loginFail) => emit(LoginFailState(loginFail.message)), 27 | (loginSuccess) => loginSuccess.requestSuccess! 28 | ? emit(LoginSuccessState(loginSuccess)) 29 | : emit(LoginFailState(loginSuccess.statusMessage!)), 30 | ); 31 | } 32 | 33 | Future userRegister() async { 34 | await userRegisterUseCase(); 35 | } 36 | 37 | Future userForgetPassword() async { 38 | await userForgetPasswordUseCase(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/cubit/login_cubit/login_state.dart: -------------------------------------------------------------------------------- 1 | part of 'login_cubit.dart'; 2 | 3 | abstract class LoginState extends Equatable { 4 | const LoginState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class LoginInitial extends LoginState {} 11 | 12 | class LoginFailState extends LoginState { 13 | final String failMessage; 14 | 15 | const LoginFailState(this.failMessage); 16 | } 17 | 18 | class LoginSuccessState extends LoginState { 19 | final Auth authData; 20 | 21 | const LoginSuccessState(this.authData); 22 | 23 | @override 24 | List get props => [authData]; 25 | } 26 | 27 | class LoginLoadingState extends LoginState {} 28 | 29 | class ObscuredState extends LoginState { 30 | final bool isObscured; 31 | const ObscuredState({ 32 | this.isObscured = true, 33 | }); 34 | 35 | @override 36 | List get props => [isObscured]; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /lib/features/auth/presentation/screens/splash_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 5 | import 'package:tmda/config/router/app_router.dart'; 6 | import 'package:tmda/core/util/assets_manager.dart'; 7 | import 'package:tmda/features/auth/presentation/screens/selection_screen.dart'; 8 | import 'package:tmda/features/shared/presentation/blocs/auth_cubit/token_cubit.dart'; 9 | import 'package:tmda/injection_container.dart'; 10 | 11 | @RoutePage() 12 | class SplashScreen extends StatelessWidget implements AutoRouteWrapper{ 13 | const SplashScreen({super.key}); 14 | @override 15 | Widget wrappedRoute(BuildContext context) { 16 | return BlocProvider( 17 | create: (context) => getIt()..checkUserLoggedIn(), 18 | child: this, 19 | ); 20 | } 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return BlocConsumer( 25 | listenWhen: (previous, current) => previous != current, 26 | listener: (context, state) { 27 | if (state is AuthenticatedState) { 28 | context.replaceRoute(const BottomNaviagationBarRoute()); 29 | } 30 | }, 31 | buildWhen: (previous, current) => previous != current, 32 | builder: (context, state) { 33 | if (state is UnAuthenticatedState) { 34 | return const SelectionScreen(); 35 | } else { 36 | return Scaffold( 37 | body: Center( 38 | child: Image.asset(AssetsManager.appLogo, width: 150.w, height: 150.h,), 39 | ), 40 | ); 41 | } 42 | }, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/features/movie/data/models/movie_cast_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/movie/domain/entities/movie_cast.dart'; 2 | 3 | class MovieCastModel extends MovieCast { 4 | const MovieCastModel({ 5 | required super.actorName, 6 | required super.movieCharacter, 7 | required super.actorPicPath, 8 | required super.actorId, 9 | }); 10 | 11 | factory MovieCastModel.fromJson(Map jsonData) { 12 | return MovieCastModel( 13 | actorName: jsonData['name'], 14 | actorPicPath: jsonData['profile_path'] ?? '', 15 | movieCharacter: jsonData['character'], 16 | actorId: jsonData['id'], 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/movie/data/models/movie_production_countries_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/movie/domain/entities/movie_production_countries.dart'; 2 | 3 | class MovieProductionCountriesModel extends MovieProductionCountries { 4 | const MovieProductionCountriesModel({ 5 | required super.countryCode, 6 | required super.countryName, 7 | }); 8 | 9 | factory MovieProductionCountriesModel.fromJson( 10 | List productionCountriesList) { 11 | if (productionCountriesList.isEmpty) { 12 | return const MovieProductionCountriesModel( 13 | countryCode: 'Unknown', 14 | countryName: 'Unknown', 15 | ); 16 | } else { 17 | return MovieProductionCountriesModel( 18 | countryCode: productionCountriesList[0]['iso_3166_1'], 19 | countryName: productionCountriesList[0]['name'], 20 | ); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/movie/data/models/movie_review_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/movie/data/models/movie_review_owner_model.dart'; 2 | import 'package:tmda/features/movie/domain/entities/movie_reviews.dart'; 3 | 4 | class MovieReviewsModel extends MovieReviews { 5 | const MovieReviewsModel({ 6 | required super.reviewContent, 7 | required super.reviewUrl, 8 | required super.movieReviewOwner, 9 | required super.reviewAuthorName, 10 | }); 11 | 12 | factory MovieReviewsModel.fromJson(Map jsonData) { 13 | return MovieReviewsModel( 14 | reviewContent: jsonData['content'], 15 | reviewUrl: jsonData['url'], 16 | movieReviewOwner: MovieReviewOwnerModel.fromJson( 17 | jsonData['author_details'], 18 | ), 19 | reviewAuthorName: jsonData['author'], 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/features/movie/data/models/movie_review_owner_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/movie/domain/entities/movie_review_owner.dart'; 2 | 3 | class MovieReviewOwnerModel extends MovieReviewOwner { 4 | const MovieReviewOwnerModel( 5 | {required super.authorName, 6 | required super.authorUserName, 7 | required super.avatarPath, 8 | required super.rating}); 9 | 10 | factory MovieReviewOwnerModel.fromJson(Map jsonData) { 11 | return MovieReviewOwnerModel( 12 | authorName: jsonData['name'], 13 | authorUserName: jsonData['username'], 14 | avatarPath: jsonData['avatar_path'] ?? '', 15 | rating: jsonData['rating'], 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/features/movie/data/models/movie_video_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/movie/domain/entities/movie_video.dart'; 2 | 3 | class MovieVideoModel extends MovieVideo{ 4 | const MovieVideoModel({ 5 | required super.name, 6 | required super.key, 7 | required super.videoType, 8 | }); 9 | 10 | factory MovieVideoModel.fromJson(List movieVideoList) { 11 | if (movieVideoList.isNotEmpty) { 12 | return MovieVideoModel( 13 | name: movieVideoList[0]['name'], 14 | key: movieVideoList[0]['key'], 15 | videoType: movieVideoList[0]['type'], 16 | ); 17 | } else { 18 | return const MovieVideoModel( 19 | name: '', 20 | key: '', 21 | videoType: '', 22 | ); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/movie/domain/entities/movie_cast.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class MovieCast extends Equatable { 4 | final String actorName; 5 | final String actorPicPath; 6 | final String movieCharacter; 7 | final int actorId; 8 | const MovieCast( { 9 | required this.actorId, 10 | required this.actorName, 11 | required this.movieCharacter, 12 | required this.actorPicPath, 13 | }); 14 | 15 | @override 16 | List get props => [actorName, actorPicPath, movieCharacter, actorId]; 17 | } 18 | -------------------------------------------------------------------------------- /lib/features/movie/domain/entities/movie_production_countries.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class MovieProductionCountries extends Equatable { 4 | final String countryCode; 5 | final String countryName; 6 | const MovieProductionCountries({ 7 | required this.countryCode, 8 | required this.countryName, 9 | }); 10 | 11 | @override 12 | List get props => [countryCode, countryName]; 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/movie/domain/entities/movie_review_owner.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class MovieReviewOwner extends Equatable { 4 | final String authorName; 5 | final String authorUserName; 6 | final String avatarPath; 7 | final dynamic rating; 8 | const MovieReviewOwner( { 9 | required this.authorName, 10 | required this.authorUserName, 11 | required this.avatarPath, 12 | required this.rating 13 | }); 14 | 15 | @override 16 | List get props => [authorName, authorUserName, avatarPath, rating]; 17 | } 18 | -------------------------------------------------------------------------------- /lib/features/movie/domain/entities/movie_reviews.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tmda/features/movie/domain/entities/movie_review_owner.dart'; 3 | 4 | class MovieReviews extends Equatable { 5 | final String reviewAuthorName; 6 | final String reviewContent; 7 | final String reviewUrl; 8 | final MovieReviewOwner movieReviewOwner; 9 | const MovieReviews({ 10 | required this.reviewAuthorName, 11 | required this.reviewContent, 12 | required this.reviewUrl, 13 | required this.movieReviewOwner, 14 | }); 15 | 16 | @override 17 | List get props => [reviewContent, reviewUrl, movieReviewOwner]; 18 | } 19 | -------------------------------------------------------------------------------- /lib/features/movie/domain/entities/movie_video.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class MovieVideo extends Equatable { 4 | final String name; 5 | final String key; 6 | final String videoType; 7 | const MovieVideo({ 8 | required this.name, 9 | required this.key, 10 | required this.videoType, 11 | }); 12 | @override 13 | List get props => [name, key, videoType]; 14 | } 15 | -------------------------------------------------------------------------------- /lib/features/movie/domain/repositories/movies_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:tmda/core/error/failure.dart'; 3 | import 'package:tmda/features/shared/domain/entities/movie.dart'; 4 | import 'package:tmda/features/movie/domain/entities/movie_details.dart'; 5 | 6 | abstract class MoviesRepository { 7 | Future>> getNowPlayingMovies(); 8 | Future>> getNewMovies({int? pageNumber}); 9 | Future>> getPopularMovies({int? pageNumber}); 10 | Future>> getTopRatedMovies({int? pageNumber}); 11 | Future> getMovieDetails({required int movieId}); 12 | Future> playMovieVideo(String movieVideoKey); 13 | Future>> getSimilarMovies({required int pageNumber, required int movieId}); 14 | Future>> getRecommendedMovies({required int pageNumber, required int movieId}); 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/movie/domain/usecases/get_movie_details_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/movie/domain/entities/movie_details.dart'; 5 | import 'package:tmda/features/movie/domain/repositories/movies_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetMovieDetailsUseCase { 9 | final MoviesRepository _moviesRepository; 10 | const GetMovieDetailsUseCase(this._moviesRepository); 11 | 12 | Future> call({required int movieId}) async { 13 | return await _moviesRepository.getMovieDetails(movieId: movieId); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/movie/domain/usecases/get_new_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/movie.dart'; 5 | import 'package:tmda/features/movie/domain/repositories/movies_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetNewMoviesUseCase { 9 | final MoviesRepository _moviesRepository; 10 | const GetNewMoviesUseCase(this._moviesRepository); 11 | Future>> call({int? pageNumber}) async{ 12 | return await _moviesRepository.getNewMovies(pageNumber: pageNumber); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/features/movie/domain/usecases/get_now_playing_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/movie.dart'; 5 | import 'package:tmda/features/movie/domain/repositories/movies_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetNowPlayingMoviesUseCase { 9 | final MoviesRepository _moviesRepository; 10 | const GetNowPlayingMoviesUseCase(this._moviesRepository); 11 | 12 | Future>> call() async{ 13 | return await _moviesRepository.getNowPlayingMovies(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/movie/domain/usecases/get_popular_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/movie.dart'; 5 | import 'package:tmda/features/movie/domain/repositories/movies_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetPopularMoviesUseCase { 9 | final MoviesRepository _moviesRepository; 10 | const GetPopularMoviesUseCase(this._moviesRepository); 11 | 12 | Future>> call({int? pageNumber}) async{ 13 | return await _moviesRepository.getPopularMovies(pageNumber: pageNumber); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/movie/domain/usecases/get_recommended_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/movie.dart'; 5 | import 'package:tmda/features/movie/domain/repositories/movies_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetAllRecommendedMoviesUseCase { 9 | final MoviesRepository _moviesRepository; 10 | const GetAllRecommendedMoviesUseCase(this._moviesRepository); 11 | 12 | Future>> call({required int pageNumber, required int movieId}) async{ 13 | return await _moviesRepository.getRecommendedMovies(pageNumber: pageNumber, movieId: movieId); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/movie/domain/usecases/get_similar_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/movie.dart'; 5 | import 'package:tmda/features/movie/domain/repositories/movies_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetAllSimilarMoviesUseCase { 9 | final MoviesRepository _moviesRepository; 10 | const GetAllSimilarMoviesUseCase(this._moviesRepository); 11 | 12 | Future>> call({required int pageNumber, required int movieId}) async{ 13 | return await _moviesRepository.getSimilarMovies(pageNumber: pageNumber, movieId: movieId); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/movie/domain/usecases/get_top_rated_movies_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/movie.dart'; 5 | import 'package:tmda/features/movie/domain/repositories/movies_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetTopRatedMoviesUseCase { 9 | final MoviesRepository _moviesRepository; 10 | const GetTopRatedMoviesUseCase(this._moviesRepository); 11 | Future>> call({int? pageNumber}) async{ 12 | return await _moviesRepository.getTopRatedMovies(pageNumber: pageNumber); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/features/movie/domain/usecases/play_movie_video_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/movie/domain/repositories/movies_repository.dart'; 5 | 6 | @lazySingleton 7 | class PlayMovieVideoUseCase { 8 | final MoviesRepository _moviesRepository; 9 | const PlayMovieVideoUseCase(this._moviesRepository); 10 | 11 | Future> call(String movieVideoKey) async{ 12 | return await _moviesRepository.playMovieVideo(movieVideoKey); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/features/movie/presentation/bloc/movie_details_cubit/movie_details_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | import 'package:tmda/core/util/enums.dart'; 5 | import 'package:tmda/features/movie/domain/entities/movie_details.dart'; 6 | import 'package:tmda/features/movie/domain/usecases/get_movie_details_usecase.dart'; 7 | import 'package:tmda/features/movie/domain/usecases/play_movie_video_usecase.dart'; 8 | 9 | part 'movie_details_state.dart'; 10 | 11 | @injectable 12 | class MovieDetailsCubit extends Cubit { 13 | final GetMovieDetailsUseCase _getMovieDetailsUseCase; 14 | final PlayMovieVideoUseCase _playMovieTrailerUseCase; 15 | 16 | MovieDetailsCubit( 17 | this._getMovieDetailsUseCase, 18 | this._playMovieTrailerUseCase, 19 | ) : super(const MovieDetailsState()); 20 | 21 | Future getMovieDetails({required int movieId}) async { 22 | final movieDetails = await _getMovieDetailsUseCase( 23 | movieId: movieId, 24 | ); 25 | movieDetails.fold( 26 | (loadMovieDetailsFail) => emit( 27 | state.copyWith( 28 | movieDetailsState: BlocState.failure, 29 | movieDetailsFailMessage: loadMovieDetailsFail.message, 30 | ), 31 | ), 32 | (movieDetailsLoaded) { 33 | emit( 34 | state.copyWith( 35 | movieDetailsState: BlocState.success, 36 | movieDetails: movieDetailsLoaded, 37 | ), 38 | ); 39 | }, 40 | ); 41 | } 42 | 43 | Future playMovieTrailer() async { 44 | await _playMovieTrailerUseCase(state.movieDetails.video.key); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/features/movie/presentation/bloc/movie_details_cubit/movie_details_state.dart: -------------------------------------------------------------------------------- 1 | part of 'movie_details_cubit.dart'; 2 | 3 | class MovieDetailsState extends Equatable { 4 | final MovieDetails movieDetails; 5 | final BlocState movieDetailsState; 6 | final String movieDetailsFailMessage; 7 | final String getMoreMoviesLikeThisFailMessage; 8 | final bool isMoviesLikeThisListReachedMax; 9 | 10 | const MovieDetailsState({ 11 | this.movieDetails = const MovieDetails(), 12 | this.movieDetailsState = BlocState.loading, 13 | this.movieDetailsFailMessage = '', 14 | this.getMoreMoviesLikeThisFailMessage = '', 15 | this.isMoviesLikeThisListReachedMax = false, 16 | }); 17 | 18 | MovieDetailsState copyWith({ 19 | MovieDetails? movieDetails, 20 | BlocState? movieDetailsState, 21 | String? movieDetailsFailMessage, 22 | String? getMoreMoviesLikeThisFailMessage, 23 | bool? isMoviesLikeThisListReachedMax, 24 | String? addOrRemoveFromWatchListFailMessage, 25 | }) { 26 | return MovieDetailsState( 27 | movieDetails: movieDetails ?? this.movieDetails, 28 | movieDetailsState: movieDetailsState ?? this.movieDetailsState, 29 | movieDetailsFailMessage: movieDetailsFailMessage ?? this.movieDetailsFailMessage, 30 | getMoreMoviesLikeThisFailMessage: getMoreMoviesLikeThisFailMessage ?? this.getMoreMoviesLikeThisFailMessage, 31 | isMoviesLikeThisListReachedMax: isMoviesLikeThisListReachedMax ?? this.isMoviesLikeThisListReachedMax, 32 | ); 33 | } 34 | 35 | @override 36 | List get props => [ 37 | movieDetails, 38 | movieDetailsState, 39 | movieDetailsFailMessage, 40 | getMoreMoviesLikeThisFailMessage, 41 | isMoviesLikeThisListReachedMax, 42 | ]; 43 | } 44 | -------------------------------------------------------------------------------- /lib/features/movie/presentation/bloc/movies_cubit/movies_state.dart: -------------------------------------------------------------------------------- 1 | part of 'movies_cubit.dart'; 2 | 3 | class MoviesState extends Equatable { 4 | final BlocState moviesState; 5 | final String moviesFailMessage; 6 | final List nowPlayingMovies; 7 | final List popularMovies; 8 | final List topRatedMovies; 9 | final List newMovies; 10 | 11 | const MoviesState({ 12 | this.nowPlayingMovies = const [], 13 | this.moviesFailMessage = '', 14 | this.newMovies = const [], 15 | this.popularMovies = const [], 16 | this.topRatedMovies = const [], 17 | this.moviesState = BlocState.loading, 18 | }); 19 | 20 | MoviesState copyWith({ 21 | int? indicatorIndex, 22 | List? nowPlayingMovies, 23 | List? popularMovies, 24 | List? topRatedMovies, 25 | List? newMovies, 26 | String? moviesFailMessage, 27 | BlocState? moviesState, 28 | }) { 29 | return MoviesState( 30 | nowPlayingMovies: nowPlayingMovies ?? this.nowPlayingMovies, 31 | popularMovies: popularMovies ?? this.popularMovies, 32 | topRatedMovies: topRatedMovies ?? this.topRatedMovies, 33 | newMovies: newMovies ?? this.newMovies, 34 | moviesState: moviesState ?? this.moviesState, 35 | moviesFailMessage: moviesFailMessage ?? this.moviesFailMessage, 36 | ); 37 | } 38 | 39 | @override 40 | List get props => [ 41 | nowPlayingMovies, 42 | popularMovies, 43 | topRatedMovies, 44 | newMovies, 45 | moviesState 46 | ]; 47 | } 48 | -------------------------------------------------------------------------------- /lib/features/movie/presentation/bloc/see_all_movies_bloc/see_all_movies_event.dart: -------------------------------------------------------------------------------- 1 | part of 'see_all_movies_bloc.dart'; 2 | 3 | abstract class SeeAllMoviesEvent extends Equatable { 4 | const SeeAllMoviesEvent(); 5 | @override 6 | List get props => []; 7 | } 8 | 9 | class GetAllNewMoviesEvent extends SeeAllMoviesEvent {} 10 | 11 | class GetAllPopularMoviesEvent extends SeeAllMoviesEvent {} 12 | 13 | class GetAllTopRatedMoviesEvent extends SeeAllMoviesEvent {} 14 | 15 | class GetAllRecommendedMoviesEvent extends SeeAllMoviesEvent { 16 | final int movieId; 17 | const GetAllRecommendedMoviesEvent({ 18 | required this.movieId, 19 | }); 20 | @override 21 | List get props => [movieId]; 22 | } 23 | 24 | class GetAllSimilarMoviesEvent extends SeeAllMoviesEvent { 25 | final int movieId; 26 | const GetAllSimilarMoviesEvent({ 27 | required this.movieId, 28 | }); 29 | @override 30 | List get props => [movieId]; 31 | } 32 | 33 | 34 | class AddOrRemoveFromWatchListEvent extends SeeAllMoviesEvent { 35 | final bool isInWatchList; 36 | final int movieId; 37 | const AddOrRemoveFromWatchListEvent({required this.isInWatchList, required this.movieId}); 38 | 39 | @override 40 | List get props => [isInWatchList, movieId]; 41 | } 42 | 43 | class CheckForMovieStatesEvent extends SeeAllMoviesEvent { 44 | final int movieId; 45 | 46 | const CheckForMovieStatesEvent(this.movieId); 47 | @override 48 | List get props => [movieId]; 49 | } 50 | 51 | class CheckForMoviesListStatesEvent extends SeeAllMoviesEvent {} -------------------------------------------------------------------------------- /lib/features/movie/presentation/bloc/see_all_movies_bloc/see_all_movies_state.dart: -------------------------------------------------------------------------------- 1 | part of 'see_all_movies_bloc.dart'; 2 | 3 | class SeeAllMoviesState extends Equatable { 4 | final List seeAllMovies; 5 | final BlocState seeAllState; 6 | final String seeAllFailMessage; 7 | final bool hasSeeAllMoviesListReachedMax; 8 | 9 | const SeeAllMoviesState({ 10 | this.seeAllMovies = const [], 11 | this.seeAllState = BlocState.loading, 12 | this.seeAllFailMessage = '', 13 | this.hasSeeAllMoviesListReachedMax = false, 14 | }); 15 | 16 | SeeAllMoviesState copyWith({ 17 | List? seeAllMovies, 18 | BlocState? seeAllState, 19 | String? seeAllFailMessage, 20 | bool? hasSeeAllMoviesListReachedMax, 21 | String? addOrRemoveFromWatchListFailMessage, 22 | String? checkForMovieStatesFailMessage, 23 | }) { 24 | return SeeAllMoviesState( 25 | seeAllMovies: seeAllMovies ?? this.seeAllMovies, 26 | seeAllState: seeAllState ?? this.seeAllState, 27 | seeAllFailMessage: seeAllFailMessage ?? this.seeAllFailMessage, 28 | hasSeeAllMoviesListReachedMax: hasSeeAllMoviesListReachedMax ?? this.hasSeeAllMoviesListReachedMax, 29 | ); 30 | } 31 | 32 | @override 33 | List get props => [ 34 | seeAllMovies, 35 | seeAllState, 36 | seeAllFailMessage, 37 | hasSeeAllMoviesListReachedMax, 38 | ]; 39 | } 40 | -------------------------------------------------------------------------------- /lib/features/person/data/datasources/person_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:injectable/injectable.dart'; 2 | import 'package:tmda/core/api/api_consumer.dart'; 3 | import 'package:tmda/core/constants/api_constants.dart'; 4 | import 'package:tmda/features/person/data/models/person_model.dart'; 5 | 6 | abstract class PersonDataSource { 7 | Future getPersonData({required int personId}); 8 | } 9 | 10 | @LazySingleton(as: PersonDataSource) 11 | class PersonDataSourceImpl extends PersonDataSource { 12 | final ApiConsumer _apiConsumer; 13 | PersonDataSourceImpl(this._apiConsumer); 14 | 15 | @override 16 | Future getPersonData({required int personId}) async { 17 | final personData = await _apiConsumer 18 | .get('${ApiConstants.personEndPoint}$personId', queryParameters: { 19 | 'append_to_response': ApiConstants.personEndPointAppendedToResponse, 20 | }); 21 | return PersonModel.fromJson(personData); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/person/data/models/person_contents_genres_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/person/domain/entities/person_contents_genres.dart'; 2 | 3 | class PersonContentsGenresModel extends PersonContentsGenres{ 4 | const PersonContentsGenresModel({required super.name, required super.id}); 5 | 6 | factory PersonContentsGenresModel.fromJson(Map jsonData){ 7 | return PersonContentsGenresModel(name: jsonData['name'], id: jsonData['id']); 8 | } 9 | } -------------------------------------------------------------------------------- /lib/features/person/data/models/person_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/person/data/models/person_movie_model.dart'; 2 | import 'package:tmda/features/person/data/models/person_tv_show_model.dart'; 3 | import 'package:tmda/features/person/domain/entities/person.dart'; 4 | 5 | class PersonModel extends Person { 6 | const PersonModel({ 7 | required super.id, 8 | required super.biography, 9 | required super.name, 10 | required super.birthDay, 11 | required super.knowingFor, 12 | required super.placeOfBirth, 13 | required super.profilePath, 14 | required super.movies, 15 | required super.tvShows, 16 | }); 17 | 18 | factory PersonModel.fromJson(Map jsonData) { 19 | final moviesList = {...(jsonData['movie_credits']['cast'] as List), ...(jsonData['movie_credits']['crew'] as List)}.toList(); 20 | final tvShowsList = {...(jsonData['tv_credits']['cast'] as List), ...(jsonData['tv_credits']['crew'] as List)}.toList(); 21 | return PersonModel( 22 | id: jsonData['id'], 23 | biography: jsonData['biography'], 24 | name: jsonData['name'], 25 | birthDay: jsonData['birthday'] ?? '', 26 | knowingFor: jsonData['known_for_department'], 27 | placeOfBirth: jsonData['place_of_birth'] ?? '', 28 | profilePath: jsonData['profile_path'] ?? '', 29 | movies: List.from(moviesList.map((movie) => PersonMovieModel.fromJson(movie))), 30 | tvShows: List.from(tvShowsList.map((tvShow) => PersonTvShowModel.fromJson(tvShow))), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/features/person/data/repositories/person_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/exception.dart'; 4 | import 'package:tmda/core/error/failure.dart'; 5 | import 'package:tmda/features/person/data/datasources/person_data_source.dart'; 6 | import 'package:tmda/features/person/data/models/person_model.dart'; 7 | import 'package:tmda/features/person/domain/repositories/person_repository.dart'; 8 | 9 | @LazySingleton(as: PersonRepository) 10 | class PersonRepositoryImpl extends PersonRepository { 11 | final PersonDataSource _personDataSource; 12 | 13 | PersonRepositoryImpl(this._personDataSource); 14 | 15 | @override 16 | Future> getPersonDetails( 17 | {required int personId}) async { 18 | try { 19 | final results = await _personDataSource.getPersonData(personId: personId); 20 | return right(results); 21 | } on ServerException catch (exception) { 22 | return left(Failure(exception.message!)); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/person/domain/entities/person.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tmda/features/person/domain/entities/person_movie.dart'; 3 | import 'package:tmda/features/person/domain/entities/person_tv_show.dart'; 4 | 5 | class Person extends Equatable { 6 | final int id; 7 | final String biography; 8 | final String name; 9 | final String birthDay; 10 | final String knowingFor; 11 | final String placeOfBirth; 12 | final String profilePath; 13 | final List movies; 14 | final List tvShows; 15 | 16 | const Person({ 17 | required this.id, 18 | required this.biography, 19 | required this.name, 20 | required this.birthDay, 21 | required this.knowingFor, 22 | required this.placeOfBirth, 23 | required this.profilePath, 24 | required this.movies, 25 | required this.tvShows, 26 | }); 27 | 28 | @override 29 | List get props => [ 30 | id, 31 | biography, 32 | name, 33 | birthDay, 34 | knowingFor, 35 | placeOfBirth, 36 | profilePath, 37 | movies, 38 | tvShows, 39 | ]; 40 | } 41 | -------------------------------------------------------------------------------- /lib/features/person/domain/entities/person_contents_genres.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class PersonContentsGenres extends Equatable{ 4 | final int id; 5 | final String name; 6 | 7 | const PersonContentsGenres({required this.id, required this.name}); 8 | 9 | @override 10 | List get props => [id, name]; 11 | } -------------------------------------------------------------------------------- /lib/features/person/domain/entities/person_movie.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tmda/features/person/domain/entities/person_contents_genres.dart'; 3 | 4 | class PersonMovie extends Equatable { 5 | final int id; 6 | final String title; 7 | final String posterPath; 8 | final String releaseDate; 9 | final String language; 10 | final dynamic voteAverage; 11 | final int voteCount; 12 | final List genres; 13 | 14 | const PersonMovie({ 15 | required this.id, 16 | required this.title, 17 | required this.posterPath, 18 | required this.releaseDate, 19 | required this.language, 20 | required this.voteAverage, 21 | required this.voteCount, 22 | required this.genres, 23 | }); 24 | 25 | PersonMovie copyWith({ 26 | int? id, 27 | String? title, 28 | String? posterPath, 29 | String? releaseDate, 30 | String? language, 31 | dynamic voteAverage, 32 | int? voteCount, 33 | List? genres, 34 | }) { 35 | return PersonMovie( 36 | id: id ?? this.id, 37 | title: title ?? this.title, 38 | posterPath: posterPath ?? this.posterPath, 39 | releaseDate: releaseDate ?? this.releaseDate, 40 | language: language ?? this.language, 41 | voteAverage: voteAverage ?? this.voteAverage, 42 | voteCount: voteCount ?? this.voteCount, 43 | genres: genres ?? this.genres, 44 | ); 45 | } 46 | 47 | @override 48 | List get props => [ 49 | id, 50 | title, 51 | posterPath, 52 | releaseDate, 53 | language, 54 | voteAverage, 55 | voteCount, 56 | genres, 57 | ]; 58 | } 59 | -------------------------------------------------------------------------------- /lib/features/person/domain/entities/person_tv_show.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tmda/features/person/domain/entities/person_contents_genres.dart'; 3 | 4 | class PersonTvShow extends Equatable { 5 | final String title; 6 | final int id; 7 | final String posterPath; 8 | final String firstAirDate; 9 | final String language; 10 | final dynamic voteAverage; 11 | final int voteCount; 12 | final List genres; 13 | 14 | const PersonTvShow({ 15 | required this.title, 16 | required this.id, 17 | required this.posterPath, 18 | required this.firstAirDate, 19 | required this.language, 20 | required this.voteAverage, 21 | required this.voteCount, 22 | required this.genres, 23 | }); 24 | 25 | PersonTvShow copyWith({ 26 | String? title, 27 | int? id, 28 | String? posterPath, 29 | String? firstAirDate, 30 | String? language, 31 | dynamic voteAverage, 32 | int? voteCount, 33 | List? genres, 34 | }) { 35 | return PersonTvShow( 36 | title: title ?? this.title, 37 | id: id ?? this.id, 38 | posterPath: posterPath ?? this.posterPath, 39 | firstAirDate: firstAirDate ?? this.firstAirDate, 40 | language: language ?? this.language, 41 | voteAverage: voteAverage ?? this.voteAverage, 42 | voteCount: voteCount ?? this.voteCount, 43 | genres: genres ?? this.genres, 44 | ); 45 | } 46 | 47 | @override 48 | List get props => [ 49 | title, 50 | id, 51 | posterPath, 52 | firstAirDate, 53 | posterPath, 54 | language, 55 | voteAverage, 56 | voteCount, 57 | genres, 58 | ]; 59 | } 60 | -------------------------------------------------------------------------------- /lib/features/person/domain/repositories/person_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:tmda/core/error/failure.dart'; 3 | import 'package:tmda/features/person/domain/entities/person.dart'; 4 | 5 | abstract class PersonRepository{ 6 | Future> getPersonDetails({required int personId}); 7 | } -------------------------------------------------------------------------------- /lib/features/person/domain/usecases/get_person_details_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/person/domain/entities/person.dart'; 5 | import 'package:tmda/features/person/domain/repositories/person_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetPersonDetailsUseCase { 9 | final PersonRepository _personRepository; 10 | const GetPersonDetailsUseCase(this._personRepository); 11 | 12 | Future> call({required int personId}) async{ 13 | return await _personRepository.getPersonDetails(personId: personId); 14 | } 15 | } -------------------------------------------------------------------------------- /lib/features/person/presentation/cubit/person_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_bloc/flutter_bloc.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/util/enums.dart'; 4 | import 'package:tmda/features/person/domain/entities/person.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:tmda/features/person/domain/usecases/get_person_details_usecase.dart'; 7 | 8 | part 'person_state.dart'; 9 | 10 | @injectable 11 | class PersonCubit extends Cubit { 12 | final GetPersonDetailsUseCase _getPersonDetailsUseCase; 13 | 14 | PersonCubit(this._getPersonDetailsUseCase) : super(const PersonState()); 15 | 16 | Future getPersonDetails(int personId) async { 17 | await _getPersonDetailsUseCase(personId: personId).then( 18 | (value) => value.fold( 19 | (loadDataFailed) => emit( 20 | state.copyWith( 21 | personDataLoadFailMessage: loadDataFailed.message, 22 | personDataState: BlocState.failure, 23 | ), 24 | ), 25 | (personDataLoaded) => emit( 26 | state.copyWith( 27 | personDataState: BlocState.success, 28 | personData: personDataLoaded, 29 | ), 30 | ), 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/features/person/presentation/cubit/person_state.dart: -------------------------------------------------------------------------------- 1 | part of 'person_cubit.dart'; 2 | 3 | class PersonState extends Equatable { 4 | final Person personData; 5 | final BlocState personDataState; 6 | final String personDataLoadFailMessage; 7 | const PersonState({ 8 | this.personData = const Person( 9 | name: '', 10 | biography: '', 11 | id: 0, 12 | birthDay: '', 13 | knowingFor: '', 14 | movies: [], 15 | placeOfBirth: '', 16 | profilePath: '', 17 | tvShows: [], 18 | ), 19 | this.personDataState = BlocState.loading, 20 | this.personDataLoadFailMessage = '', 21 | }); 22 | 23 | PersonState copyWith({ 24 | Person? personData, 25 | BlocState? personDataState, 26 | String? personDataLoadFailMessage, 27 | double? animatedHeight, 28 | bool? isTextExpanded 29 | }) { 30 | return PersonState( 31 | personData: personData ?? this.personData, 32 | personDataState: personDataState ?? this.personDataState, 33 | personDataLoadFailMessage: personDataLoadFailMessage ?? this.personDataLoadFailMessage, 34 | ); 35 | } 36 | 37 | @override 38 | List get props => [personData, personDataLoadFailMessage, personDataState]; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /lib/features/search/data/models/person_search_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/search/domain/entities/person_search.dart'; 2 | 3 | class PersonSearchModel extends PersonSearch { 4 | const PersonSearchModel({ 5 | required super.id, 6 | required super.name, 7 | required super.knowingFor, 8 | required super.profilePath, 9 | }); 10 | 11 | factory PersonSearchModel.fromJson(Map jsonData) { 12 | return PersonSearchModel( 13 | id: jsonData['id'], 14 | name: jsonData['name'], 15 | knowingFor: jsonData['known_for_department'] ?? '', 16 | profilePath: jsonData['profile_path'] ?? '', 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/search/data/models/search_genre_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/search/domain/entities/search_genre.dart'; 2 | 3 | class SearchGenreModel extends SearchGenre{ 4 | const SearchGenreModel({required super.name, required super.id}); 5 | 6 | factory SearchGenreModel.fromJson(Map jsonData){ 7 | return SearchGenreModel(name: jsonData['name'], id: jsonData['id']); 8 | } 9 | } -------------------------------------------------------------------------------- /lib/features/search/domain/entities/movie_search.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tmda/features/search/domain/entities/search_genre.dart'; 3 | 4 | class MovieSearch extends Equatable { 5 | final int id; 6 | final String title; 7 | final String posterPath; 8 | final String releaseDate; 9 | final String language; 10 | final dynamic voteAverage; 11 | final int voteCount; 12 | final List genres; 13 | 14 | const MovieSearch({ 15 | required this.id, 16 | required this.title, 17 | required this.posterPath, 18 | required this.releaseDate, 19 | required this.voteAverage, 20 | required this.voteCount, 21 | required this.genres, 22 | required this.language, 23 | }); 24 | 25 | @override 26 | List get props => [ 27 | id, 28 | title, 29 | posterPath, 30 | language, 31 | releaseDate, 32 | voteAverage, 33 | voteCount, 34 | genres, 35 | ]; 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/search/domain/entities/person_search.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class PersonSearch extends Equatable { 4 | final int id; 5 | final String name; 6 | final String knowingFor; 7 | final String profilePath; 8 | 9 | const PersonSearch({ 10 | required this.id, 11 | required this.name, 12 | required this.knowingFor, 13 | required this.profilePath, 14 | }); 15 | 16 | @override 17 | List get props => [ 18 | id, 19 | name, 20 | knowingFor, 21 | profilePath, 22 | ]; 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/search/domain/entities/search_genre.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class SearchGenre extends Equatable { 4 | final int id; 5 | final String name; 6 | const SearchGenre({ 7 | required this.name, 8 | required this.id, 9 | }); 10 | 11 | @override 12 | List get props => [id, name]; 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/search/domain/entities/tv_show_search.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tmda/features/search/domain/entities/search_genre.dart'; 3 | 4 | class TvShowSearch extends Equatable { 5 | final String title; 6 | final int id; 7 | final String posterPath; 8 | final String firstAirDate; 9 | final String language; 10 | final dynamic voteAverage; 11 | final int voteCount; 12 | final List genres; 13 | 14 | const TvShowSearch({ 15 | required this.title, 16 | required this.id, 17 | required this.posterPath, 18 | required this.language, 19 | required this.voteAverage, 20 | required this.voteCount, 21 | required this.genres, 22 | required this.firstAirDate, 23 | }); 24 | 25 | @override 26 | List get props => [ 27 | id, 28 | posterPath, 29 | title, 30 | language, 31 | voteAverage, 32 | voteCount, 33 | genres, 34 | firstAirDate, 35 | ]; 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/search/domain/repositories/search_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:tmda/core/error/failure.dart'; 3 | import 'package:tmda/features/search/domain/entities/movie_search.dart'; 4 | import 'package:tmda/features/search/domain/entities/person_search.dart'; 5 | import 'package:tmda/features/search/domain/entities/tv_show_search.dart'; 6 | 7 | abstract class SearchRepository{ 8 | Future getSessionId(); 9 | Future>> searchForMovie({required String movieName, required String sessionId, required int pageNumber}); 10 | Future>> searchForTvShow({required String tvShowName, required String sessionId, required int pageNumber}); 11 | Future>> searchForPerson({required String personName, required int pageNumber}); 12 | } -------------------------------------------------------------------------------- /lib/features/search/domain/usecases/get_search_session_id_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:injectable/injectable.dart'; 2 | import 'package:tmda/features/search/domain/repositories/search_repository.dart'; 3 | 4 | @lazySingleton 5 | class GetSearchSessionIdUseCase{ 6 | final SearchRepository _searchRepository; 7 | const GetSearchSessionIdUseCase(this._searchRepository); 8 | 9 | Future call() async{ 10 | return await _searchRepository.getSessionId(); 11 | } 12 | } -------------------------------------------------------------------------------- /lib/features/search/domain/usecases/search_for_movie_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/search/domain/entities/movie_search.dart'; 5 | import 'package:tmda/features/search/domain/repositories/search_repository.dart'; 6 | 7 | @lazySingleton 8 | class SearchForMovieUseCase{ 9 | final SearchRepository _searchRepository; 10 | const SearchForMovieUseCase(this._searchRepository); 11 | 12 | Future>> call({required String movieName, required String sessionId, required int pageNumber}) async{ 13 | return await _searchRepository.searchForMovie(movieName: movieName, sessionId: sessionId, pageNumber: pageNumber); 14 | } 15 | } -------------------------------------------------------------------------------- /lib/features/search/domain/usecases/search_for_person_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/search/domain/entities/person_search.dart'; 5 | import 'package:tmda/features/search/domain/repositories/search_repository.dart'; 6 | 7 | @lazySingleton 8 | class SearchForPersonUseCase{ 9 | final SearchRepository _searchRepository; 10 | const SearchForPersonUseCase(this._searchRepository); 11 | 12 | Future>> call({required String personName, required String sessionId, required int pageNumber}) async{ 13 | return await _searchRepository.searchForPerson(personName: personName, pageNumber: pageNumber); 14 | } 15 | } -------------------------------------------------------------------------------- /lib/features/search/domain/usecases/search_for_tv_show_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/search/domain/entities/tv_show_search.dart'; 5 | import 'package:tmda/features/search/domain/repositories/search_repository.dart'; 6 | 7 | @lazySingleton 8 | class SearchForTvShowUseCase{ 9 | final SearchRepository _searchRepository; 10 | const SearchForTvShowUseCase(this._searchRepository); 11 | 12 | Future>> call({required String tvShowName, required String sessionId, required int pageNumber}) async{ 13 | return await _searchRepository.searchForTvShow(tvShowName: tvShowName, sessionId: sessionId, pageNumber: pageNumber); 14 | } 15 | } -------------------------------------------------------------------------------- /lib/features/search/presentation/components/custom_search_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:tmda/core/icons/solar_system_icons.dart'; 4 | import 'package:tmda/core/util/color_manager.dart'; 5 | import 'package:tmda/core/util/extensions.dart'; 6 | 7 | class CustomSearchField extends StatelessWidget { 8 | const CustomSearchField({ 9 | super.key, 10 | required this.textEditingController, 11 | required this.onChanged, 12 | }); 13 | 14 | final TextEditingController textEditingController; 15 | final void Function(String searchText) onChanged; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return SizedBox( 20 | height: 45.h, 21 | child: TextField( 22 | textInputAction: TextInputAction.search, 23 | onChanged: onChanged, 24 | controller: textEditingController, 25 | style: context.textTheme.bodyLarge!.copyWith( 26 | fontWeight: FontWeight.w500, 27 | ), 28 | cursorColor: ColorsManager.primaryColor, 29 | decoration: InputDecoration( 30 | filled: true, 31 | fillColor: Colors.black.withValues(alpha: 0.37), 32 | hintText: '${context.tr.search}..', 33 | hintStyle: context.textTheme.bodyMedium!.copyWith( 34 | color: ColorsManager.inActiveColor, 35 | ), 36 | prefixIcon: const Icon( 37 | SolarSystemIcons.search, 38 | color: ColorsManager.inActiveColor, 39 | ), 40 | border: OutlineInputBorder( 41 | borderRadius: BorderRadius.circular(10).w, 42 | borderSide: BorderSide.none, 43 | ), 44 | ), 45 | ), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/features/search/presentation/components/no_search_results.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:tmda/core/animations/custom_fade_animation.dart'; 4 | import 'package:tmda/core/icons/solar_system_icons.dart'; 5 | import 'package:tmda/core/util/color_manager.dart'; 6 | import 'package:tmda/core/util/extensions.dart'; 7 | 8 | class NoSearchResults extends StatelessWidget { 9 | const NoSearchResults({ 10 | super.key, 11 | }); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return CustomFadeAnimation( 16 | child: Center( 17 | child: Column( 18 | mainAxisAlignment: MainAxisAlignment.center, 19 | children: [ 20 | const Icon( 21 | SolarSystemIcons.error, 22 | color: ColorsManager.primaryColor, 23 | size: 70, 24 | ), 25 | SizedBox(height: 20.h), 26 | Text( 27 | context.tr.noSearchResults, 28 | style: context.textTheme.titleMedium! 29 | .copyWith(color: ColorsManager.darkPrimary), 30 | ), 31 | ], 32 | ), 33 | ), 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/features/search/presentation/components/search_initial_body.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 | import 'package:tmda/core/icons/solar_system_icons.dart'; 4 | import 'package:tmda/core/util/color_manager.dart'; 5 | import 'package:tmda/core/util/extensions.dart'; 6 | 7 | class SearchInitialBody extends StatelessWidget { 8 | const SearchInitialBody({ 9 | super.key, 10 | }); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Center( 15 | child: Column( 16 | mainAxisAlignment: MainAxisAlignment.center, 17 | children: [ 18 | const Icon( 19 | SolarSystemIcons.search, 20 | color: ColorsManager.primaryColor, 21 | size: 70, 22 | ), 23 | SizedBox(height: 30.h), 24 | Text( 25 | context.tr.initialSearchTitle, 26 | style: context.textTheme.titleLarge! 27 | .copyWith(color: ColorsManager.primaryColor), 28 | ), 29 | SizedBox(height: 10.h), 30 | Text( 31 | context.tr.initialSearchSubTitle, 32 | style: context.textTheme.titleSmall!.copyWith( 33 | fontSize: 16, 34 | color: Colors.white, 35 | ), 36 | ), 37 | ], 38 | ), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/features/shared/data/models/account_states_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/shared/domain/entities/account_states.dart'; 2 | 3 | class AccountStatesModel extends AccountStates { 4 | const AccountStatesModel({required super.isInWatchList, super.contentId}); 5 | 6 | factory AccountStatesModel.fromJson(Map jsonData) { 7 | return AccountStatesModel( 8 | isInWatchList: jsonData['watchlist'] ?? false, 9 | contentId: jsonData['content_id'] ?? 0, 10 | ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/features/shared/data/models/auth_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/shared/domain/entities/auth.dart'; 2 | 3 | class AuthModel extends Auth { 4 | const AuthModel({ 5 | super.requestToken, 6 | super.sessionId, 7 | super.requestSuccess, 8 | super.statusMessage, 9 | }); 10 | 11 | factory AuthModel.fromJson(Map jsonData) { 12 | return AuthModel( 13 | requestSuccess: jsonData['success'] ?? false, 14 | requestToken: jsonData['request_token'] ?? "", 15 | sessionId: jsonData['session_id'] ?? "", 16 | statusMessage: jsonData['status_message'] ?? "", 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/shared/data/models/movie_genres_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/shared/domain/entities/movie_genre.dart'; 2 | 3 | class MovieGenresModel extends MovieGenres { 4 | const MovieGenresModel({required super.name, required super.id}); 5 | 6 | factory MovieGenresModel.fromJson(Map jsonData) { 7 | return MovieGenresModel( 8 | id: jsonData['id'], 9 | name: jsonData['name'], 10 | ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/features/shared/data/models/tv_show_genres_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/shared/domain/entities/tv_show_genres.dart'; 2 | 3 | class TvShowGenresModel extends TvShowGenres { 4 | const TvShowGenresModel({required super.id, required super.name}); 5 | 6 | factory TvShowGenresModel.fromJson(Map jsonData) { 7 | return TvShowGenresModel( 8 | id: jsonData['id'], 9 | name: jsonData['name'], 10 | ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/features/shared/data/repositories/local_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/exception.dart'; 4 | import 'package:tmda/core/error/failure.dart'; 5 | import 'package:tmda/features/shared/data/datasources/local_data_source.dart'; 6 | import 'package:tmda/features/shared/data/models/auth_model.dart'; 7 | import 'package:tmda/features/shared/domain/repositories/local_repository.dart'; 8 | 9 | @LazySingleton(as: LocalRepository) 10 | class LocalRepositoryImpl extends LocalRepository{ 11 | final LocalDataSource _localDataSource; 12 | 13 | LocalRepositoryImpl(this._localDataSource); 14 | @override 15 | Future> checkUserLoginSession() async{ 16 | try { 17 | String sessionId = await _localDataSource.getSessionId(); 18 | return right(AuthModel(sessionId: sessionId, requestSuccess: true)); 19 | } on CacheException catch(exception) { 20 | return left(Failure(exception.message!)); 21 | } 22 | } 23 | 24 | @override 25 | Future getSessionId() async { 26 | return await _localDataSource.getSessionId(); 27 | } 28 | } -------------------------------------------------------------------------------- /lib/features/shared/domain/entities/account_states.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class AccountStates extends Equatable { 4 | final int? contentId; 5 | final bool isInWatchList; 6 | 7 | const AccountStates({ 8 | required this.isInWatchList, 9 | this.contentId, 10 | }); 11 | 12 | @override 13 | List get props => [isInWatchList, contentId]; 14 | } 15 | -------------------------------------------------------------------------------- /lib/features/shared/domain/entities/auth.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class Auth extends Equatable{ 4 | final String? requestToken; 5 | final String? sessionId; 6 | final bool? requestSuccess; 7 | final String? statusMessage; 8 | 9 | const Auth({this.requestToken, this.sessionId, this.requestSuccess, this.statusMessage}); 10 | 11 | @override 12 | List get props => [requestSuccess, requestToken, sessionId, statusMessage]; 13 | 14 | } -------------------------------------------------------------------------------- /lib/features/shared/domain/entities/movie_genre.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class MovieGenres extends Equatable { 4 | final int id; 5 | final String name; 6 | const MovieGenres({ 7 | required this.name, 8 | required this.id, 9 | }); 10 | 11 | @override 12 | List get props => [id, name]; 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/shared/domain/entities/tv_show_genres.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class TvShowGenres extends Equatable { 4 | final int id; 5 | final String name; 6 | 7 | const TvShowGenres({required this.id, required this.name}); 8 | @override 9 | List get props => []; 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/shared/domain/repositories/local_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:tmda/features/shared/domain/entities/auth.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | 5 | abstract class LocalRepository{ 6 | Future> checkUserLoginSession(); 7 | Future getSessionId(); 8 | } -------------------------------------------------------------------------------- /lib/features/shared/domain/repositories/watch_list_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:tmda/core/error/failure.dart'; 3 | import 'package:tmda/features/shared/domain/entities/movie.dart'; 4 | import 'package:tmda/features/shared/domain/entities/tv_show.dart'; 5 | 6 | abstract class WatchListRepository{ 7 | Future>> getMoviesWatchListIdsSet(); 8 | Future>> getTvShowsWatchListIdsSet(); 9 | Future>> getMoviesWatchList({int? pageNumber}); 10 | Future>> getTvShowsWatchList({int? pageNumber}); 11 | Future> addOrRemoveMovieFromWatchList({required bool isInWatchList, required int movieId}); 12 | Future> addOrRemoveTvShowFromWatchList({required bool isInWatchList, required int tvShowId}); 13 | } -------------------------------------------------------------------------------- /lib/features/shared/domain/usecases/add_or_remove_movie_from_watchlist_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/movie.dart'; 5 | import 'package:tmda/features/shared/domain/repositories/watch_list_repository.dart'; 6 | 7 | @lazySingleton 8 | class AddOrRemoveMovieFromWatchListUseCase{ 9 | final WatchListRepository _watchListRepository; 10 | const AddOrRemoveMovieFromWatchListUseCase(this._watchListRepository); 11 | 12 | Future> call({required int movieId, required bool isInWatchList}) async{ 13 | return await _watchListRepository.addOrRemoveMovieFromWatchList(isInWatchList: isInWatchList, movieId: movieId); 14 | } 15 | } -------------------------------------------------------------------------------- /lib/features/shared/domain/usecases/add_or_remove_tvshow_from_watchlist_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/tv_show.dart'; 5 | import 'package:tmda/features/shared/domain/repositories/watch_list_repository.dart'; 6 | 7 | @lazySingleton 8 | class AddOrRemoveTvShowFromWatchListUseCase{ 9 | final WatchListRepository _watchListRepository; 10 | const AddOrRemoveTvShowFromWatchListUseCase(this._watchListRepository); 11 | 12 | Future> call({required int tvShowId, required bool isInWatchList}) async{ 13 | return await _watchListRepository.addOrRemoveTvShowFromWatchList(isInWatchList: isInWatchList, tvShowId: tvShowId); 14 | } 15 | } -------------------------------------------------------------------------------- /lib/features/shared/domain/usecases/check_user_login_session_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/auth.dart'; 5 | import 'package:tmda/features/shared/domain/repositories/local_repository.dart'; 6 | 7 | @lazySingleton 8 | class CheckUserLoginSessionUseCase { 9 | final LocalRepository _localRepository; 10 | const CheckUserLoginSessionUseCase(this._localRepository); 11 | 12 | Future> call() async{ 13 | return await _localRepository.checkUserLoginSession(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/shared/domain/usecases/get_movies_watch_list_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/movie.dart'; 5 | import 'package:tmda/features/shared/domain/repositories/watch_list_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetMoviesWatchListUseCase{ 9 | final WatchListRepository _watchListRepository; 10 | 11 | const GetMoviesWatchListUseCase(this._watchListRepository); 12 | Future>> call({int? pageNumber}) async{ 13 | return await _watchListRepository.getMoviesWatchList(pageNumber: pageNumber); 14 | } 15 | } -------------------------------------------------------------------------------- /lib/features/shared/domain/usecases/get_movies_watchlist_ids_set_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/repositories/watch_list_repository.dart'; 5 | 6 | @lazySingleton 7 | class GetMoviesWatchListIdsSetUseCase { 8 | final WatchListRepository _watchListRepository; 9 | 10 | const GetMoviesWatchListIdsSetUseCase(this._watchListRepository); 11 | 12 | Future>> call() async { 13 | return await _watchListRepository.getMoviesWatchListIdsSet(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/shared/domain/usecases/get_session_id_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:injectable/injectable.dart'; 2 | import 'package:tmda/features/shared/domain/repositories/local_repository.dart'; 3 | 4 | @lazySingleton 5 | class GetSessionIdUseCase { 6 | final LocalRepository _localRepository; 7 | const GetSessionIdUseCase(this._localRepository); 8 | 9 | Future call() async{ 10 | return await _localRepository.getSessionId(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/features/shared/domain/usecases/get_tv_shows_watch_list_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/tv_show.dart'; 5 | import 'package:tmda/features/shared/domain/repositories/watch_list_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetTvShowsWatchListUseCase{ 9 | final WatchListRepository _watchListRepository; 10 | 11 | const GetTvShowsWatchListUseCase(this._watchListRepository); 12 | 13 | Future>> call({int? pageNumber}) async{ 14 | return await _watchListRepository.getTvShowsWatchList(pageNumber: pageNumber); 15 | } 16 | } -------------------------------------------------------------------------------- /lib/features/shared/domain/usecases/get_tv_shows_watchlist_ids_set_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/repositories/watch_list_repository.dart'; 5 | 6 | @lazySingleton 7 | class GetTvShowsWatchListIdsSetUseCase{ 8 | final WatchListRepository _watchListRepository; 9 | 10 | const GetTvShowsWatchListIdsSetUseCase(this._watchListRepository); 11 | 12 | Future>> call() async{ 13 | return await _watchListRepository.getTvShowsWatchListIdsSet(); 14 | } 15 | } -------------------------------------------------------------------------------- /lib/features/shared/presentation/blocs/auth_cubit/token_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | import 'package:tmda/features/shared/domain/entities/auth.dart'; 5 | import 'package:tmda/features/shared/domain/usecases/check_user_login_session_usecase.dart'; 6 | import 'package:tmda/features/auth/domain/usecases/user_register_usecase.dart'; 7 | 8 | part 'token_state.dart'; 9 | 10 | @injectable 11 | class TokenCubit extends Cubit { 12 | final CheckUserLoginSessionUseCase _checkUserLoggedInUseCase; 13 | final UserRegisterUseCase _userRegisterUseCase; 14 | 15 | TokenCubit( 16 | this._checkUserLoggedInUseCase, 17 | this._userRegisterUseCase, 18 | ) : super(AuthInitialState()); 19 | 20 | Future checkUserLoggedIn() async { 21 | final response = await _checkUserLoggedInUseCase(); 22 | 23 | response.fold( 24 | (authFailure) => emit( 25 | UnAuthenticatedState(), 26 | ), 27 | (authSuccess) => emit( 28 | AuthenticatedState(authSuccess), 29 | ), 30 | ); 31 | } 32 | 33 | Future userRegister() async { 34 | await _userRegisterUseCase(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /lib/features/shared/presentation/blocs/auth_cubit/token_state.dart: -------------------------------------------------------------------------------- 1 | part of 'token_cubit.dart'; 2 | 3 | abstract class AuthState extends Equatable { 4 | const AuthState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class AuthInitialState extends AuthState {} 11 | 12 | class AuthenticatedState extends AuthState { 13 | final Auth authData; 14 | 15 | const AuthenticatedState(this.authData); 16 | 17 | @override 18 | List get props => [authData]; 19 | } 20 | 21 | class UnAuthenticatedState extends AuthState {} 22 | -------------------------------------------------------------------------------- /lib/features/shared/presentation/blocs/watchlist_bloc/watchlist_event.dart: -------------------------------------------------------------------------------- 1 | part of 'watchlist_bloc.dart'; 2 | 3 | class WatchListEvent extends Equatable{ 4 | const WatchListEvent(); 5 | @override 6 | List get props => []; 7 | } 8 | 9 | class GetMoviesWatchListIdsEvent extends WatchListEvent{} 10 | 11 | class GetTvShowsWatchListIdsEvent extends WatchListEvent{} 12 | 13 | class GetMoviesWatchListEvent extends WatchListEvent{} 14 | 15 | class GetTvShowsWatchListEvent extends WatchListEvent{} 16 | 17 | class AddOrRemoveMovieFromWatchListEvent extends WatchListEvent{ 18 | final int movieId; 19 | final bool isInWatchList; 20 | const AddOrRemoveMovieFromWatchListEvent({required this.movieId, required this.isInWatchList}); 21 | @override 22 | List get props => [movieId, isInWatchList]; 23 | } 24 | 25 | class AddOrRemoveTvShowFromWatchListEvent extends WatchListEvent{ 26 | final int tvShowId; 27 | final bool isInWatchList; 28 | const AddOrRemoveTvShowFromWatchListEvent({required this.tvShowId, required this.isInWatchList}); 29 | @override 30 | List get props => [tvShowId, isInWatchList]; 31 | } 32 | 33 | class ChangeMoviesWatchListViewScrollState extends WatchListEvent{ 34 | final bool isMoviesWatchListViewHasReachedMaxScroll; 35 | const ChangeMoviesWatchListViewScrollState({required this.isMoviesWatchListViewHasReachedMaxScroll}); 36 | @override 37 | List get props => [isMoviesWatchListViewHasReachedMaxScroll]; 38 | } 39 | 40 | class ChangeTvShowsWatchListViewScrollState extends WatchListEvent{ 41 | final bool isTvShowsWatchListViewHasReachedMaxScroll; 42 | const ChangeTvShowsWatchListViewScrollState({required this.isTvShowsWatchListViewHasReachedMaxScroll}); 43 | @override 44 | List get props => [isTvShowsWatchListViewHasReachedMaxScroll]; 45 | } -------------------------------------------------------------------------------- /lib/features/tv/data/models/tv_show_cast_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/tv/domain/entities/tv_show_cast.dart'; 2 | 3 | class TvShowCastModel extends TvShowCast { 4 | const TvShowCastModel({ 5 | required super.actorId, 6 | required super.actorName, 7 | required super.movieCharacter, 8 | required super.actorPicPath, 9 | }); 10 | 11 | factory TvShowCastModel.fromJson(Map jsonData) { 12 | return TvShowCastModel( 13 | actorId: jsonData['id'], 14 | actorName: jsonData['name'], 15 | movieCharacter: jsonData['character'], 16 | actorPicPath: jsonData['profile_path'] ?? '', 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/tv/data/models/tv_show_network_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/tv/domain/entities/tv_show_network.dart'; 2 | 3 | class TvShowNetworkModel extends TvShowNetwork { 4 | const TvShowNetworkModel({ 5 | required super.id, 6 | required super.name, 7 | }); 8 | 9 | factory TvShowNetworkModel.fromJson(List tvShowNetworkList) { 10 | if (tvShowNetworkList.isNotEmpty) { 11 | return TvShowNetworkModel( 12 | id: tvShowNetworkList[0]['id'], 13 | name: tvShowNetworkList[0]['name'], 14 | ); 15 | }else{ 16 | return const TvShowNetworkModel( 17 | id: 0, 18 | name: 'NaN', 19 | ); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/features/tv/data/models/tv_show_production_countries_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/tv/domain/entities/tv_show_production_country.dart'; 2 | 3 | class TvShowProductionCountryModel extends TvShowProductionCountry { 4 | const TvShowProductionCountryModel({ 5 | required super.countryCode, 6 | required super.countryName, 7 | }); 8 | 9 | factory TvShowProductionCountryModel.fromJson(List productionCountriesList){ 10 | if (productionCountriesList.isEmpty) { 11 | return const TvShowProductionCountryModel( 12 | countryCode: 'Unknown', 13 | countryName: 'Unknown', 14 | ); 15 | } else { 16 | return TvShowProductionCountryModel( 17 | countryCode: productionCountriesList[0]['iso_3166_1'], 18 | countryName: productionCountriesList[0]['name'], 19 | ); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/features/tv/data/models/tv_show_review_owner_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/tv/domain/entities/tv_show_review_owner.dart'; 2 | 3 | class TvShowReviewOwnerModel extends TvShowReviewOwner { 4 | const TvShowReviewOwnerModel({ 5 | required super.authorName, 6 | required super.authorUserName, 7 | required super.avatarPath, 8 | required super.rating, 9 | }); 10 | 11 | factory TvShowReviewOwnerModel.fromJson(Map jsonData) { 12 | return TvShowReviewOwnerModel( 13 | authorName: jsonData['name'], 14 | authorUserName: jsonData['username'], 15 | avatarPath: jsonData['avatar_path'] ?? '', 16 | rating: jsonData['rating'], 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/features/tv/data/models/tv_show_reviews_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/tv/data/models/tv_show_review_owner_model.dart'; 2 | import 'package:tmda/features/tv/domain/entities/tv_show_reviews.dart'; 3 | 4 | class TvShowReviewsModel extends TvShowReviews { 5 | const TvShowReviewsModel({ 6 | required super.authorName, 7 | required super.reviewContent, 8 | required super.reviewUrl, 9 | required super.reviewOwner, 10 | }); 11 | 12 | factory TvShowReviewsModel.fromJson(Map jsonData) { 13 | return TvShowReviewsModel( 14 | authorName: jsonData['author'], 15 | reviewContent: jsonData['content'], 16 | reviewUrl: jsonData['url'], 17 | reviewOwner: TvShowReviewOwnerModel.fromJson(jsonData['author_details']) 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/features/tv/data/models/tv_show_video_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:tmda/features/tv/domain/entities/tv_show_video.dart'; 2 | 3 | class TvShowVideoModel extends TvShowVideo { 4 | const TvShowVideoModel({ 5 | required super.name, 6 | required super.key, 7 | required super.videoType, 8 | }); 9 | 10 | factory TvShowVideoModel.fromJson(List tvShowVideosList) { 11 | if (tvShowVideosList.isNotEmpty) { 12 | return TvShowVideoModel( 13 | name: tvShowVideosList[0]['name'], 14 | key: tvShowVideosList[0]['key'], 15 | videoType: tvShowVideosList[0]['type'], 16 | ); 17 | } else { 18 | return const TvShowVideoModel( 19 | name: '', 20 | key: '', 21 | videoType: '', 22 | ); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/tv/domain/entities/tv_show_cast.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class TvShowCast extends Equatable { 4 | final String actorName; 5 | final String actorPicPath; 6 | final String movieCharacter; 7 | final int actorId; 8 | const TvShowCast( { 9 | required this.actorId, 10 | required this.actorName, 11 | required this.movieCharacter, 12 | required this.actorPicPath, 13 | }); 14 | 15 | @override 16 | List get props => [actorName, actorPicPath, movieCharacter, actorId]; 17 | } 18 | -------------------------------------------------------------------------------- /lib/features/tv/domain/entities/tv_show_network.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:equatable/equatable.dart'; 3 | 4 | class TvShowNetwork extends Equatable{ 5 | final int id; 6 | final String name; 7 | const TvShowNetwork({ 8 | required this.id, 9 | required this.name, 10 | }); 11 | 12 | @override 13 | List get props => [id, name]; 14 | } 15 | -------------------------------------------------------------------------------- /lib/features/tv/domain/entities/tv_show_production_country.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class TvShowProductionCountry extends Equatable { 4 | final String countryCode; 5 | final String countryName; 6 | const TvShowProductionCountry({ 7 | required this.countryCode, 8 | required this.countryName, 9 | }); 10 | 11 | @override 12 | List get props => [countryCode, countryName]; 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/tv/domain/entities/tv_show_review_owner.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class TvShowReviewOwner extends Equatable { 4 | final String authorName; 5 | final String authorUserName; 6 | final String avatarPath; 7 | final dynamic rating; 8 | const TvShowReviewOwner( { 9 | required this.authorName, 10 | required this.authorUserName, 11 | required this.avatarPath, 12 | required this.rating 13 | }); 14 | 15 | @override 16 | List get props => [authorName, authorUserName, avatarPath, rating]; 17 | } 18 | -------------------------------------------------------------------------------- /lib/features/tv/domain/entities/tv_show_reviews.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:tmda/features/tv/domain/entities/tv_show_review_owner.dart'; 3 | 4 | class TvShowReviews extends Equatable { 5 | final String authorName; 6 | final String reviewContent; 7 | final String reviewUrl; 8 | final TvShowReviewOwner reviewOwner; 9 | const TvShowReviews({ 10 | required this.authorName, 11 | required this.reviewContent, 12 | required this.reviewUrl, 13 | required this.reviewOwner 14 | }); 15 | 16 | @override 17 | List get props => [reviewContent, reviewUrl, authorName, reviewOwner]; 18 | } 19 | -------------------------------------------------------------------------------- /lib/features/tv/domain/entities/tv_show_video.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class TvShowVideo extends Equatable { 4 | final String name; 5 | final String key; 6 | final String videoType; 7 | const TvShowVideo({ 8 | required this.name, 9 | required this.key, 10 | required this.videoType, 11 | }); 12 | @override 13 | List get props => [name, key, videoType]; 14 | } 15 | -------------------------------------------------------------------------------- /lib/features/tv/domain/repositories/tv_shows_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:tmda/core/error/failure.dart'; 3 | import 'package:tmda/features/tv/domain/entities/tv_show_details.dart'; 4 | import 'package:tmda/features/shared/domain/entities/tv_show.dart'; 5 | 6 | abstract class TvShowsRepository{ 7 | Future>> getTvShowsAiringToday(int pageNumber); 8 | Future>> getTvShowsAiringThisWeek(int pageNumber); 9 | Future>> getPopularTvShows(int pageNumber); 10 | Future>> getTopRatedTvShows(int pageNumber); 11 | Future> getTvShowDetails({required int tvShowId}); 12 | Future> playTvShowVideo({required String youtubeVideoKey}); 13 | Future>> getSimilarTvShows({required int pageNumber, required int tvShowId}); 14 | Future>> getRecommendedTvShows({required int pageNumber, required int tvShowId}); 15 | } -------------------------------------------------------------------------------- /lib/features/tv/domain/usecases/get_popular_tv_shows.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/tv_show.dart'; 5 | import 'package:tmda/features/tv/domain/repositories/tv_shows_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetPopularTvShowsUseCase { 9 | final TvShowsRepository _tvShowsRepository; 10 | const GetPopularTvShowsUseCase(this._tvShowsRepository); 11 | 12 | Future>> call(int pageNumber) async{ 13 | return await _tvShowsRepository.getPopularTvShows(pageNumber); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/tv/domain/usecases/get_recommended_tv_shows_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/tv_show.dart'; 5 | import 'package:tmda/features/tv/domain/repositories/tv_shows_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetRecommendedTvShowsUseCase { 9 | final TvShowsRepository _tvShowsRepository; 10 | const GetRecommendedTvShowsUseCase(this._tvShowsRepository); 11 | 12 | Future>> call({required int pageNumber, required int tvShowId}) async{ 13 | return await _tvShowsRepository.getRecommendedTvShows(pageNumber: pageNumber, tvShowId: tvShowId); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/tv/domain/usecases/get_similar_tv_shows_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/tv_show.dart'; 5 | import 'package:tmda/features/tv/domain/repositories/tv_shows_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetSimilarTvShowsUseCase { 9 | final TvShowsRepository _tvShowsRepository; 10 | const GetSimilarTvShowsUseCase(this._tvShowsRepository); 11 | 12 | Future>> call({required int pageNumber, required int tvShowId}) async{ 13 | return await _tvShowsRepository.getSimilarTvShows(pageNumber: pageNumber, tvShowId: tvShowId); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/tv/domain/usecases/get_top_rated_tv_shows.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/tv_show.dart'; 5 | import 'package:tmda/features/tv/domain/repositories/tv_shows_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetTopRatedTvShowsUseCase { 9 | final TvShowsRepository _tvShowsRepository; 10 | const GetTopRatedTvShowsUseCase(this._tvShowsRepository); 11 | 12 | Future>> call(int pageNumber) async{ 13 | return await _tvShowsRepository.getTopRatedTvShows(pageNumber); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/tv/domain/usecases/get_tv_show_details_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/tv/domain/entities/tv_show_details.dart'; 5 | import 'package:tmda/features/tv/domain/repositories/tv_shows_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetTvShowDetailsUseCase { 9 | final TvShowsRepository _tvShowsRepository; 10 | const GetTvShowDetailsUseCase(this._tvShowsRepository); 11 | 12 | Future> call(int tvShowId) async{ 13 | return await _tvShowsRepository.getTvShowDetails(tvShowId: tvShowId); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/tv/domain/usecases/get_tv_shows_airing_this_week_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/tv_show.dart'; 5 | import 'package:tmda/features/tv/domain/repositories/tv_shows_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetTvShowsAiringThisWeekUseCase { 9 | final TvShowsRepository _tvShowsRepository; 10 | const GetTvShowsAiringThisWeekUseCase(this._tvShowsRepository); 11 | 12 | Future>> call(int pageNumber) async{ 13 | return await _tvShowsRepository.getTvShowsAiringThisWeek(pageNumber); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/tv/domain/usecases/get_tv_shows_airing_today.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/shared/domain/entities/tv_show.dart'; 5 | import 'package:tmda/features/tv/domain/repositories/tv_shows_repository.dart'; 6 | 7 | @lazySingleton 8 | class GetTvShowsAiringTodayUseCase { 9 | final TvShowsRepository _tvShowsRepository; 10 | const GetTvShowsAiringTodayUseCase(this._tvShowsRepository); 11 | 12 | Future>> call(int pageNumber) async{ 13 | return await _tvShowsRepository.getTvShowsAiringToday(pageNumber); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/features/tv/domain/usecases/play_tv_show_video_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:tmda/core/error/failure.dart'; 4 | import 'package:tmda/features/tv/domain/repositories/tv_shows_repository.dart'; 5 | 6 | @lazySingleton 7 | class PlayTvShowVideoUseCase { 8 | final TvShowsRepository _tvShowsRepository; 9 | const PlayTvShowVideoUseCase(this._tvShowsRepository); 10 | Future> call({required String youtubeVideoKey}) async{ 11 | return await _tvShowsRepository.playTvShowVideo(youtubeVideoKey: youtubeVideoKey); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/tv/presentation/bloc/see_all_tv_shows_bloc/see_all_tv_shows_event.dart: -------------------------------------------------------------------------------- 1 | part of 'see_all_tv_shows_bloc.dart'; 2 | 3 | abstract class SeeAllTvShowsEvent extends Equatable { 4 | const SeeAllTvShowsEvent(); 5 | @override 6 | List get props => []; 7 | } 8 | 9 | class GetAllAiringTodayTvShowsEvent extends SeeAllTvShowsEvent {} 10 | 11 | class GetAllPopularTvShowsEvent extends SeeAllTvShowsEvent {} 12 | 13 | class GetAllTopRatedTvShowsEvent extends SeeAllTvShowsEvent {} 14 | 15 | class GetAllRecommendedTvShowsEvent extends SeeAllTvShowsEvent { 16 | final int tvShowId; 17 | const GetAllRecommendedTvShowsEvent({ 18 | required this.tvShowId, 19 | }); 20 | @override 21 | List get props => [tvShowId]; 22 | } 23 | 24 | class GetAllSimilarTvShowsEvent extends SeeAllTvShowsEvent { 25 | final int tvShowId; 26 | const GetAllSimilarTvShowsEvent({ 27 | required this.tvShowId, 28 | }); 29 | @override 30 | List get props => [tvShowId]; 31 | } -------------------------------------------------------------------------------- /lib/features/tv/presentation/bloc/see_all_tv_shows_bloc/see_all_tv_shows_state.dart: -------------------------------------------------------------------------------- 1 | part of 'see_all_tv_shows_bloc.dart'; 2 | 3 | class SeeAllTvShowsState extends Equatable { 4 | final List seeAllTvShows; 5 | final BlocState seeAllState; 6 | final String seeAllFailMessage; 7 | final bool hasSeeAllTvShowsListReachedMax; 8 | 9 | const SeeAllTvShowsState({ 10 | this.seeAllTvShows = const [], 11 | this.seeAllState = BlocState.loading, 12 | this.seeAllFailMessage = '', 13 | this.hasSeeAllTvShowsListReachedMax = false, 14 | }); 15 | 16 | SeeAllTvShowsState copyWith({ 17 | List? seeAllTvShows, 18 | BlocState? seeAllState, 19 | String? seeAllFailMessage, 20 | bool? hasSeeAllTvShowsListReachedMax, 21 | String? addOrRemoveFromWatchListFailMessage, 22 | String? checkForTvShowStatesFailMessage, 23 | }) { 24 | return SeeAllTvShowsState( 25 | seeAllTvShows: seeAllTvShows ?? this.seeAllTvShows, 26 | seeAllState: seeAllState ?? this.seeAllState, 27 | seeAllFailMessage: seeAllFailMessage ?? this.seeAllFailMessage, 28 | hasSeeAllTvShowsListReachedMax: hasSeeAllTvShowsListReachedMax ?? this.hasSeeAllTvShowsListReachedMax, 29 | ); 30 | } 31 | 32 | @override 33 | List get props => [ 34 | seeAllTvShows, 35 | seeAllState, 36 | seeAllFailMessage, 37 | hasSeeAllTvShowsListReachedMax, 38 | ]; 39 | } 40 | -------------------------------------------------------------------------------- /lib/features/tv/presentation/bloc/tv_show_cubit/tv_show_state.dart: -------------------------------------------------------------------------------- 1 | part of 'tv_show_cubit.dart'; 2 | 3 | class TvShowsState extends Equatable { 4 | final BlocState tvShowsState; 5 | final String tvShowsFailMessage; 6 | final List airingTodayTvShows; 7 | final List airingThisWeekTvShows; 8 | final List popularTvShows; 9 | final List topRatedTvShows; 10 | 11 | 12 | const TvShowsState({ 13 | this.tvShowsState = BlocState.loading, 14 | this.tvShowsFailMessage = '', 15 | this.airingTodayTvShows = const [], 16 | this.airingThisWeekTvShows = const [], 17 | this.popularTvShows = const [], 18 | this.topRatedTvShows = const [], 19 | }); 20 | 21 | TvShowsState copyWith({ 22 | BlocState? tvShowsState, 23 | String? tvShowsFailMessage, 24 | List? airingTodayTvShows, 25 | List? airingThisWeekTvShows, 26 | List? topRatedTvShows, 27 | List? popularTvShows, 28 | }) { 29 | return TvShowsState( 30 | tvShowsState: tvShowsState ?? this.tvShowsState, 31 | tvShowsFailMessage: tvShowsFailMessage ?? this.tvShowsFailMessage, 32 | airingTodayTvShows: airingTodayTvShows ?? this.airingTodayTvShows, 33 | airingThisWeekTvShows: 34 | airingThisWeekTvShows ?? this.airingThisWeekTvShows, 35 | popularTvShows: popularTvShows ?? this.popularTvShows, 36 | topRatedTvShows: topRatedTvShows ?? this.topRatedTvShows, 37 | ); 38 | } 39 | 40 | @override 41 | List get props => [ 42 | airingTodayTvShows, 43 | airingThisWeekTvShows, 44 | popularTvShows, 45 | topRatedTvShows, 46 | ]; 47 | } 48 | -------------------------------------------------------------------------------- /lib/injection_container.dart: -------------------------------------------------------------------------------- 1 | import 'package:get_it/get_it.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'injection_container.config.dart'; 4 | final getIt = GetIt.instance; 5 | 6 | @InjectableInit() 7 | void configureDependencies() => getIt.init(); -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:hive_flutter/hive_flutter.dart'; 4 | import 'package:tmda/app.dart'; 5 | import 'package:tmda/bloc_observer.dart'; 6 | import 'package:tmda/injection_container.dart'; 7 | 8 | void main() async { 9 | WidgetsFlutterBinding.ensureInitialized(); 10 | await Hive.initFlutter(); 11 | configureDependencies(); 12 | Bloc.observer = MyBlocObserver(); 13 | runApp(const TmdaApp()); 14 | } -------------------------------------------------------------------------------- /lib/register_module.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:flutter_secure_storage/flutter_secure_storage.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | import 'package:tmda/core/api/api_consumer.dart'; 5 | import 'package:tmda/core/api/dio_consumer.dart'; 6 | import 'package:tmda/injection_container.dart'; 7 | 8 | @module 9 | abstract class RegisterModule { 10 | @injectable 11 | Dio get dioClient => Dio(); 12 | 13 | @lazySingleton 14 | ApiConsumer get dioConsumer => DioApiConsumer(dioClient: getIt()); 15 | 16 | @lazySingleton 17 | FlutterSecureStorage get localStorage => const FlutterSecureStorage(); 18 | } 19 | 20 | class $RegisterModule extends RegisterModule {} 21 | -------------------------------------------------------------------------------- /lib/route_observer.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | 5 | class MyRouteObserver extends AutoRouterObserver { 6 | @override 7 | void didPush(Route route, Route? previousRoute) { 8 | debugPrint('New route pushed: ${route.settings.name}'); 9 | } 10 | 11 | @override 12 | void didPop(Route route, Route? previousRoute) { 13 | debugPrint('Route Popped : ${route.settings.name}'); 14 | } 15 | 16 | @override 17 | void didRemove(Route route, Route? previousRoute) { 18 | debugPrint('Route Removed : ${route.settings.name}'); 19 | } 20 | 21 | @override 22 | void didReplace({Route? newRoute, Route? oldRoute}) { 23 | debugPrint('OldRoute : ${oldRoute!.settings.name} was replaced by ${newRoute!.settings.name}'); 24 | } 25 | 26 | 27 | // only override to observer tab routes 28 | @override 29 | void didInitTabRoute(TabPageRoute route, TabPageRoute? previousRoute) { 30 | debugPrint('Tab route visited: ${route.name}'); 31 | } 32 | 33 | @override 34 | void didChangeTabRoute(TabPageRoute route, TabPageRoute previousRoute) { 35 | debugPrint('Tab route re-visited: ${route.name}'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /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 | #include 11 | 12 | void fl_register_plugins(FlPluginRegistry* registry) { 13 | g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = 14 | fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); 15 | flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); 16 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = 17 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); 18 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); 19 | } 20 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | flutter_secure_storage_linux 7 | url_launcher_linux 8 | ) 9 | 10 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 11 | ) 12 | 13 | set(PLUGIN_BUNDLED_LIBRARIES) 14 | 15 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 16 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 17 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 20 | endforeach(plugin) 21 | 22 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 25 | endforeach(ffi_plugin) 26 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import flutter_secure_storage_macos 9 | import path_provider_foundation 10 | import sqflite_darwin 11 | import url_launcher_macos 12 | 13 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 14 | FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) 15 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 16 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) 17 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 18 | } 19 | -------------------------------------------------------------------------------- /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 | 32 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 33 | target 'RunnerTests' do 34 | inherit! :search_paths 35 | end 36 | end 37 | 38 | post_install do |installer| 39 | installer.pods_project.targets.each do |target| 40 | flutter_additional_macos_build_settings(target) 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /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 = tmda 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.flutter.tmda 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. 15 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController() 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 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import FlutterMacOS 2 | import Cocoa 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tmda", 3 | "short_name": "tmda", 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 12 | void RegisterPlugins(flutter::PluginRegistry* registry) { 13 | FlutterSecureStorageWindowsPluginRegisterWithRegistrar( 14 | registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); 15 | UrlLauncherWindowsRegisterWithRegistrar( 16 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 17 | } 18 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | flutter_secure_storage_windows 7 | url_launcher_windows 8 | ) 9 | 10 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 11 | ) 12 | 13 | set(PLUGIN_BUNDLED_LIBRARIES) 14 | 15 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 16 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 17 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 20 | endforeach(plugin) 21 | 22 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 25 | endforeach(ffi_plugin) 26 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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"tmda", 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Camp-IO/TMDA-Flutter/c1684c3b90da742557773ac04bdf1ce4fc942656/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------