├── .gitignore ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── ic_launcher_icon-playstore.png │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── ruben │ │ │ │ └── fun_box │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ ├── icon_splash.png │ │ │ └── launch_background.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher_icon.xml │ │ │ └── ic_launcher_icon_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_icon.png │ │ │ ├── ic_launcher_icon_foreground.png │ │ │ └── ic_launcher_icon_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_icon.png │ │ │ ├── ic_launcher_icon_foreground.png │ │ │ └── ic_launcher_icon_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_icon.png │ │ │ ├── ic_launcher_icon_foreground.png │ │ │ └── ic_launcher_icon_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_icon.png │ │ │ ├── ic_launcher_icon_foreground.png │ │ │ └── ic_launcher_icon_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_icon.png │ │ │ ├── ic_launcher_icon_foreground.png │ │ │ └── ic_launcher_icon_round.png │ │ │ └── values │ │ │ ├── ic_launcher_icon_background.xml │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── fun_box_android.iml ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── settings.gradle └── settings_aar.gradle ├── data ├── .gitignore ├── .metadata ├── README.md ├── data.iml ├── data_android.iml ├── lib │ ├── di │ │ ├── di.config.dart │ │ └── di.dart │ └── repository │ │ ├── cast_repository_impl.dart │ │ ├── config_repository_impl.dart │ │ ├── details_repository_impl.dart │ │ ├── filter_repository_impl.dart │ │ ├── movies_repository_impl.dart │ │ ├── person_repository_impl.dart │ │ ├── search_repository_impl.dart │ │ ├── shows_repository_impl.dart │ │ ├── trending_repository_impl.dart │ │ └── video_repository_impl.dart └── pubspec.yaml ├── domain ├── .gitignore ├── .metadata ├── README.md ├── domain.iml ├── domain_android.iml ├── lib │ ├── di │ │ ├── di.config.dart │ │ └── di.dart │ ├── model │ │ ├── cast_record.dart │ │ ├── config_record.dart │ │ ├── movie_details_record.dart │ │ ├── movie_show_genres_record.dart │ │ ├── movies_shows_record.dart │ │ ├── person_credits_record.dart │ │ ├── person_info_record.dart │ │ ├── show_details_record.dart │ │ ├── trailer_record.dart │ │ └── trending_people_record.dart │ ├── repository │ │ ├── cast_repository.dart │ │ ├── config_repository.dart │ │ ├── details_repository.dart │ │ ├── filter_repository.dart │ │ ├── movies_repository.dart │ │ ├── person_repository.dart │ │ ├── search_repository.dart │ │ ├── shows_repository.dart │ │ ├── trending_repository.dart │ │ └── video_repository.dart │ └── usecase │ │ ├── cast │ │ ├── movie_cast_use_case.dart │ │ └── show_cast_use_case.dart │ │ ├── details │ │ ├── movie_details_use_case.dart │ │ └── show_details_use_case.dart │ │ ├── filter │ │ ├── movie_filter_use_case.dart │ │ └── show_filter_use_case.dart │ │ ├── get_config_use_case.dart │ │ ├── movies │ │ ├── current_playing_movies_use_case.dart │ │ ├── latest_movies_use_case.dart │ │ ├── movies_by_genres_use_case.dart │ │ ├── popular_movies_use_case.dart │ │ ├── top_rated_movies_use_case.dart │ │ └── upcoming_movies_use_case.dart │ │ ├── person │ │ ├── person_credits_use_case.dart │ │ └── person_info_use_case.dart │ │ ├── search_movies_shows_use_case.dart │ │ ├── shows │ │ ├── airing_today_shows_use_case.dart │ │ ├── current_playing_shows_use_case.dart │ │ ├── latest_shows_use_case.dart │ │ ├── popular_shows_use_case.dart │ │ ├── shows_by_genres_use_case.dart │ │ └── top_rated_shows_use_case.dart │ │ ├── trending │ │ ├── trending_movies_use_case.dart │ │ ├── trending_people_use_case.dart │ │ └── trending_shows_use_case.dart │ │ └── video │ │ ├── movie_trailer_use_case.dart │ │ └── show_trailer_use_case.dart └── pubspec.yaml ├── fonts ├── ironclad.ttf └── metropolis.otf ├── fun_box.iml ├── images └── error_image.png ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── 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 │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.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 ├── lib ├── bloc │ ├── all │ │ ├── trending_bloc.dart │ │ ├── trending_event.dart │ │ └── trending_state.dart │ ├── cast │ │ ├── movie_show_cast_bloc.dart │ │ ├── movie_show_cast_event.dart │ │ └── movie_show_cast_state.dart │ ├── details │ │ ├── movie_show_details_bloc.dart │ │ ├── movie_show_details_event.dart │ │ └── movie_show_details_state.dart │ ├── filter │ │ ├── movies_shows_filter_bloc.dart │ │ ├── movies_shows_filter_event.dart │ │ └── movies_shows_filter_state.dart │ ├── movieshow │ │ ├── movies_shows_bloc.dart │ │ ├── movies_shows_event.dart │ │ └── movies_shows_state.dart │ ├── person │ │ ├── person_details_bloc.dart │ │ ├── person_details_event.dart │ │ └── person_details_state.dart │ ├── search │ │ ├── movies_shows_search_bloc.dart │ │ ├── movies_shows_search_event.dart │ │ └── movies_shows_search_state.dart │ └── video │ │ ├── movie_show_trailer_bloc.dart │ │ ├── movie_show_trailer_event.dart │ │ └── movie_show_trailer_state.dart ├── config │ ├── configurations.dart │ └── default_config.dart ├── di │ ├── di.config.dart │ └── di.dart ├── main.dart ├── presentation │ ├── common │ │ ├── common_display_tiles.dart │ │ ├── common_error_ui.dart │ │ ├── common_people_tiles.dart │ │ ├── common_search_bar.dart │ │ └── common_widgets.dart │ ├── details │ │ ├── movie_show_details.dart │ │ └── widgets │ │ │ ├── movie_show_cast.dart │ │ │ └── movie_show_info.dart │ ├── filter │ │ ├── filters.dart │ │ └── movies_shows_filters.dart │ ├── home │ │ ├── home.dart │ │ └── widgets │ │ │ ├── trending_movies.dart │ │ │ ├── trending_people.dart │ │ │ └── trending_shows.dart │ ├── movieshow │ │ ├── movies_shows.dart │ │ └── widgets │ │ │ ├── currently_playing.dart │ │ │ └── most_popular.dart │ ├── person │ │ ├── person_details.dart │ │ └── widgets │ │ │ ├── person_credits.dart │ │ │ └── person_info.dart │ ├── search │ │ └── search.dart │ ├── ui_constants.dart │ └── video │ │ ├── movie_show_trailer.dart │ │ └── video_player.dart └── utils │ ├── app_constants.dart │ ├── app_navigator_observer.dart │ └── app_utility.dart ├── pubspec.yaml ├── remote ├── .gitignore ├── .metadata ├── README.md ├── lib │ ├── datasource │ │ ├── movies_shows_data_source.dart │ │ └── movies_shows_data_source_impl.dart │ ├── di │ │ ├── di.config.dart │ │ └── di.dart │ ├── http_client.dart │ ├── model │ │ ├── cast_request.dart │ │ ├── details_request.dart │ │ ├── genres_request.dart │ │ ├── movies_shows_genre_request.dart │ │ ├── movies_shows_request.dart │ │ ├── page_request.dart │ │ ├── person_credits_request.dart │ │ ├── person_info_request.dart │ │ ├── search_request.dart │ │ ├── trailer_request.dart │ │ └── trending_request.dart │ └── util │ │ ├── api_constants.dart │ │ └── http_util.dart ├── pubspec.yaml ├── remote.iml └── remote_android.iml └── screenshots ├── home.jpg ├── movie_show_details.jpg ├── movie_show_filters.jpg ├── movie_show_search.jpg ├── movies.jpg ├── person_details.jpg ├── tv_show_details.jpg └── tv_shows.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | # If you're building an application, you may want to check-in your pubspec.lock 8 | pubspec.lock 9 | 10 | # Directory created by dartdoc 11 | # If you don't generate documentation locally you can remove this line. 12 | doc/api/ 13 | 14 | # Avoid committing generated Javascript files: 15 | *.dart.js 16 | *.info.json # Produced by the --dump-info flag. 17 | *.js # When generated by dart2js. Don't specify *.js if your 18 | # project includes source files written in JavaScript. 19 | *.js_ 20 | *.js.deps 21 | *.js.map 22 | .flutter-plugins 23 | .flutter-plugins-dependencies 24 | .idea 25 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Fun Box 2 | 3 | Movies and Tv shows finder. 4 | 5 | - Multi-module MVVM Clean Architecture 6 | - Bloc Pattern 7 | - GetIt and Injectable for dependency injection 8 | - The Movie DB for movies and TV shows. [TheMovieDB](https://developers.themoviedb.org) 9 | 10 | ## Libraries Used 11 | - [Bloc](https://pub.dev/packages/flutter_bloc) 12 | - [GetIt](https://pub.dev/packages/get_it) 13 | - [Injectable](https://pub.dev/packages/injectable) 14 | - [YouTubePlayer](https://pub.dev/packages/youtube_player_flutter) 15 | - [Http](https://pub.dev/packages/http) 16 | 17 | ## App Screens 18 | 19 | - Home Screen 20 | 21 | ![](screenshots/home.jpg) 22 | 23 | - Movies Sceen 24 | 25 | ![](screenshots/movies.jpg) 26 | 27 | - TV Shows Screen 28 | 29 | ![](screenshots/tv_shows.jpg) 30 | 31 | - Movies Details 32 | 33 | ![](screenshots/movie_show_details.jpg) 34 | 35 | - TV Shows Details 36 | 37 | ![](screenshots/tv_show_details.jpg) 38 | 39 | - Cast Details 40 | 41 | ![](screenshots/person_details.jpg) 42 | 43 | - Search movies & shows 44 | 45 | ![](screenshots/movie_show_search.jpg) 46 | 47 | - Filter movies & shows 48 | 49 | ![](screenshots/movie_show_filters.jpg) 50 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 29 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | applicationId "com.ruben.funbox" 41 | minSdkVersion 19 42 | targetSdkVersion 30 43 | versionCode flutterVersionCode.toInteger() 44 | versionName flutterVersionName 45 | } 46 | 47 | buildTypes { 48 | release { 49 | // TODO: Add your own signing config for the release build. 50 | // Signing with the debug keys for now, so `flutter run --release` works. 51 | signingConfig signingConfigs.debug 52 | } 53 | } 54 | } 55 | 56 | flutter { 57 | source '../..' 58 | } 59 | 60 | dependencies { 61 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 62 | } 63 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 23 | 27 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /android/app/src/main/ic_launcher_icon-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/ic_launcher_icon-playstore.png -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/ruben/fun_box/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.ruben.fun_box 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/icon_splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/drawable/icon_splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_icon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_icon_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-hdpi/ic_launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_icon_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-hdpi/ic_launcher_icon_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_icon_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-hdpi/ic_launcher_icon_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-mdpi/ic_launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_icon_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-mdpi/ic_launcher_icon_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_icon_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-mdpi/ic_launcher_icon_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xhdpi/ic_launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_icon_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xhdpi/ic_launcher_icon_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_icon_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xhdpi/ic_launcher_icon_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_icon_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_icon_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_icon_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_icon_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_icon_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_icon_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_icon_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_icon_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/ic_launcher_icon_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.4.32' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.3' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/fun_box_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | android.enableR8=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /android/settings_aar.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /data/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | .idea/ 8 | .vagrant/ 9 | .sconsign.dblite 10 | .svn/ 11 | 12 | *.swp 13 | profile 14 | 15 | DerivedData/ 16 | 17 | .generated/ 18 | 19 | *.pbxuser 20 | *.mode1v3 21 | *.mode2v3 22 | *.perspectivev3 23 | 24 | !default.pbxuser 25 | !default.mode1v3 26 | !default.mode2v3 27 | !default.perspectivev3 28 | 29 | xcuserdata 30 | 31 | *.moved-aside 32 | 33 | *.pyc 34 | *sync/ 35 | Icon? 36 | .tags* 37 | 38 | build/ 39 | .android/ 40 | .ios/ 41 | .flutter-plugins 42 | .flutter-plugins-dependencies 43 | 44 | # Symbolication related 45 | app.*.symbols 46 | 47 | # Obfuscation related 48 | app.*.map.json 49 | -------------------------------------------------------------------------------- /data/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6 8 | channel: stable 9 | 10 | project_type: module 11 | -------------------------------------------------------------------------------- /data/README.md: -------------------------------------------------------------------------------- 1 | # data 2 | 3 | A new flutter module project. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.dev/). 9 | 10 | For instructions integrating Flutter modules to your existing applications, 11 | see the [add-to-app documentation](https://flutter.dev/docs/development/add-to-app). 12 | -------------------------------------------------------------------------------- /data/data.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /data/data_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /data/lib/di/di.config.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | // ************************************************************************** 4 | // InjectableConfigGenerator 5 | // ************************************************************************** 6 | 7 | import 'package:domain/repository/cast_repository.dart' as _i3; 8 | import 'package:domain/repository/config_repository.dart' as _i6; 9 | import 'package:domain/repository/details_repository.dart' as _i8; 10 | import 'package:domain/repository/filter_repository.dart' as _i10; 11 | import 'package:domain/repository/movies_repository.dart' as _i12; 12 | import 'package:domain/repository/person_repository.dart' as _i14; 13 | import 'package:domain/repository/search_repository.dart' as _i16; 14 | import 'package:domain/repository/shows_repository.dart' as _i18; 15 | import 'package:domain/repository/trending_repository.dart' as _i20; 16 | import 'package:domain/repository/video_repository.dart' as _i22; 17 | import 'package:get_it/get_it.dart' as _i1; 18 | import 'package:injectable/injectable.dart' as _i2; 19 | import 'package:remote/datasource/movies_shows_data_source.dart' as _i5; 20 | 21 | import '../repository/cast_repository_impl.dart' as _i4; 22 | import '../repository/config_repository_impl.dart' as _i7; 23 | import '../repository/details_repository_impl.dart' as _i9; 24 | import '../repository/filter_repository_impl.dart' as _i11; 25 | import '../repository/movies_repository_impl.dart' as _i13; 26 | import '../repository/person_repository_impl.dart' as _i15; 27 | import '../repository/search_repository_impl.dart' as _i17; 28 | import '../repository/shows_repository_impl.dart' as _i19; 29 | import '../repository/trending_repository_impl.dart' as _i21; 30 | import '../repository/video_repository_impl.dart' 31 | as _i23; // ignore_for_file: unnecessary_lambdas 32 | 33 | // ignore_for_file: lines_longer_than_80_chars 34 | /// initializes the registration of provided dependencies inside of [GetIt] 35 | _i1.GetIt $initDataGetIt(_i1.GetIt get, 36 | {String? environment, _i2.EnvironmentFilter? environmentFilter}) { 37 | final gh = _i2.GetItHelper(get, environment, environmentFilter); 38 | gh.singleton<_i3.CastRepository>( 39 | _i4.CastRepositoryImpl(get<_i5.MoviesShowsDataSource>())); 40 | gh.singleton<_i6.ConfigRepository>( 41 | _i7.ConfigRepositoryImpl(get<_i5.MoviesShowsDataSource>())); 42 | gh.singleton<_i8.DetailsRepository>( 43 | _i9.DetailsRepositoryImpl(get<_i5.MoviesShowsDataSource>())); 44 | gh.singleton<_i10.FilterRepository>( 45 | _i11.FilterRepositoryImpl(get<_i5.MoviesShowsDataSource>())); 46 | gh.singleton<_i12.MoviesRepository>( 47 | _i13.MoviesRepositoryImpl(get<_i5.MoviesShowsDataSource>())); 48 | gh.singleton<_i14.PersonRepository>( 49 | _i15.PersonRepositoryImpl(get<_i5.MoviesShowsDataSource>())); 50 | gh.singleton<_i16.SearchRepository>( 51 | _i17.SearchRepositoryImpl(get<_i5.MoviesShowsDataSource>())); 52 | gh.singleton<_i18.ShowsRepository>( 53 | _i19.ShowsRepositoryImpl(get<_i5.MoviesShowsDataSource>())); 54 | gh.singleton<_i20.TrendingRepository>( 55 | _i21.TrendingRepositoryImpl(get<_i5.MoviesShowsDataSource>())); 56 | gh.singleton<_i22.VideoRepository>( 57 | _i23.VideoRepositoryImpl(get<_i5.MoviesShowsDataSource>())); 58 | return get; 59 | } 60 | -------------------------------------------------------------------------------- /data/lib/di/di.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/di/di.config.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @InjectableInit( 5 | initializerName: r'$initDataGetIt' 6 | ) 7 | Future configureDataInjection(final getIt) async => $initDataGetIt(getIt); -------------------------------------------------------------------------------- /data/lib/repository/cast_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/cast_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:remote/datasource/movies_shows_data_source.dart'; 4 | import 'package:remote/model/cast_request.dart'; 5 | 6 | @Singleton(as: CastRepository) 7 | class CastRepositoryImpl extends CastRepository { 8 | final MoviesShowsDataSource moviesShowsDataSource; 9 | 10 | CastRepositoryImpl(this.moviesShowsDataSource); 11 | 12 | @override 13 | Future getMovieCast(String type, double id) { 14 | return moviesShowsDataSource.getCast(CastRequest(type, id)); 15 | } 16 | 17 | @override 18 | Future getShowCast(String type, double id) { 19 | return moviesShowsDataSource.getCast(CastRequest(type, id)); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /data/lib/repository/config_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/config_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:remote/datasource/movies_shows_data_source.dart'; 4 | 5 | @Singleton(as: ConfigRepository) 6 | class ConfigRepositoryImpl extends ConfigRepository { 7 | final MoviesShowsDataSource moviesShowsDataSource; 8 | 9 | ConfigRepositoryImpl(this.moviesShowsDataSource); 10 | 11 | @override 12 | Future getConfig() { 13 | return moviesShowsDataSource.getConfig(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/lib/repository/details_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/details_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:remote/datasource/movies_shows_data_source.dart'; 4 | import 'package:remote/model/details_request.dart'; 5 | 6 | @Singleton(as: DetailsRepository) 7 | class DetailsRepositoryImpl extends DetailsRepository { 8 | final MoviesShowsDataSource moviesShowsDataSource; 9 | 10 | DetailsRepositoryImpl(this.moviesShowsDataSource); 11 | 12 | @override 13 | Future getMovieDetails(String type, double id) { 14 | return moviesShowsDataSource.getDetails(DetailsRequest(type: type, id: id)); 15 | } 16 | 17 | @override 18 | Future getShowDetails(String type, double id) { 19 | return moviesShowsDataSource.getDetails(DetailsRequest(type: type, id: id)); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /data/lib/repository/filter_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/filter_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:remote/datasource/movies_shows_data_source.dart'; 4 | import 'package:remote/model/genres_request.dart'; 5 | 6 | @Singleton(as: FilterRepository) 7 | class FilterRepositoryImpl extends FilterRepository { 8 | final MoviesShowsDataSource moviesShowsDataSource; 9 | 10 | FilterRepositoryImpl(this.moviesShowsDataSource); 11 | 12 | @override 13 | Future getGenres(String type) { 14 | return moviesShowsDataSource.getGenres(GenresRequest(type: type)); 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /data/lib/repository/movies_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/movies_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:remote/datasource/movies_shows_data_source.dart'; 4 | import 'package:remote/model/movies_shows_genre_request.dart'; 5 | import 'package:remote/model/movies_shows_request.dart'; 6 | import 'package:remote/model/page_request.dart'; 7 | 8 | @Singleton(as: MoviesRepository) 9 | class MoviesRepositoryImpl extends MoviesRepository { 10 | final MoviesShowsDataSource moviesShowsDataSource; 11 | 12 | MoviesRepositoryImpl(this.moviesShowsDataSource); 13 | 14 | @override 15 | Future getCurrentPlayingMovies(int page) { 16 | return moviesShowsDataSource 17 | .getCurrentPlayingMovies(PageRequest(page: page)); 18 | } 19 | 20 | @override 21 | Future getPopularMovies(String type, int page) { 22 | return moviesShowsDataSource 23 | .getPopularMoviesShows(MoviesShowsRequest(type: type, page: page)); 24 | } 25 | 26 | @override 27 | Future getLatestMovies(String type, int page) { 28 | return moviesShowsDataSource 29 | .getLatestMoviesShows(MoviesShowsRequest(type: type, page: page)); 30 | } 31 | 32 | @override 33 | Future getTopRatedMovies(String type, int page) { 34 | return moviesShowsDataSource 35 | .getTopRatedMoviesShows(MoviesShowsRequest(type: type, page: page)); 36 | } 37 | 38 | @override 39 | Future getUpcomingMovies(int page) { 40 | return moviesShowsDataSource.getUpcomingMovies(PageRequest(page: page)); 41 | } 42 | 43 | @override 44 | Future getMoviesByGenre(String type, int genreId, int page) { 45 | return moviesShowsDataSource.getMoviesShowsByGenre( 46 | MoviesShowsGenreRequest(type: type, genreId: genreId, page: page)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /data/lib/repository/person_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/person_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:remote/datasource/movies_shows_data_source.dart'; 4 | import 'package:remote/model/person_credits_request.dart'; 5 | import 'package:remote/model/person_info_request.dart'; 6 | 7 | @Singleton(as: PersonRepository) 8 | class PersonRepositoryImpl extends PersonRepository { 9 | final MoviesShowsDataSource moviesShowsDataSource; 10 | 11 | PersonRepositoryImpl(this.moviesShowsDataSource); 12 | 13 | @override 14 | Future getPersonCredits(double id) { 15 | return moviesShowsDataSource.getPersonCredits(PersonCreditsRequest(id: id)); 16 | } 17 | 18 | @override 19 | Future getPersonInfo(double id) { 20 | return moviesShowsDataSource.getPersonInfo(PersonInfoRequest(id: id)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /data/lib/repository/search_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/search_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:remote/datasource/movies_shows_data_source.dart'; 4 | import 'package:remote/model/search_request.dart'; 5 | 6 | @Singleton(as: SearchRepository) 7 | class SearchRepositoryImpl extends SearchRepository { 8 | final MoviesShowsDataSource moviesShowsDataSource; 9 | 10 | SearchRepositoryImpl(this.moviesShowsDataSource); 11 | 12 | @override 13 | Future searchMoviesShows(String searchTerm) { 14 | return moviesShowsDataSource 15 | .searchMoviesShows(SearchRequest(searchTerm: searchTerm)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /data/lib/repository/shows_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/shows_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:remote/datasource/movies_shows_data_source.dart'; 4 | import 'package:remote/model/movies_shows_genre_request.dart'; 5 | import 'package:remote/model/movies_shows_request.dart'; 6 | import 'package:remote/model/page_request.dart'; 7 | 8 | @Singleton(as: ShowsRepository) 9 | class ShowsRepositoryImpl extends ShowsRepository { 10 | final MoviesShowsDataSource moviesShowsDataSource; 11 | 12 | ShowsRepositoryImpl(this.moviesShowsDataSource); 13 | 14 | @override 15 | Future getCurrentPlayingShows(int page) { 16 | return moviesShowsDataSource 17 | .getCurrentPlayingShows(PageRequest(page: page)); 18 | } 19 | 20 | @override 21 | Future getPopularShows(String type, int page) { 22 | return moviesShowsDataSource 23 | .getPopularMoviesShows(MoviesShowsRequest(type: type, page: page)); 24 | } 25 | 26 | @override 27 | Future getLatestShows(String type, int page) { 28 | return moviesShowsDataSource 29 | .getLatestMoviesShows(MoviesShowsRequest(type: type, page: page)); 30 | } 31 | 32 | @override 33 | Future getTopRatedShows(String type, int page) { 34 | return moviesShowsDataSource 35 | .getTopRatedMoviesShows(MoviesShowsRequest(type: type, page: page)); 36 | } 37 | 38 | @override 39 | Future getAiringTodayShows(int page) { 40 | return moviesShowsDataSource.getAiringTodayShows(PageRequest(page: page)); 41 | } 42 | 43 | @override 44 | Future getShowsByGenre(String type, int genreId, int page) { 45 | return moviesShowsDataSource.getMoviesShowsByGenre( 46 | MoviesShowsGenreRequest(type: type, genreId: genreId, page: page)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /data/lib/repository/trending_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/trending_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:remote/datasource/movies_shows_data_source.dart'; 4 | import 'package:remote/model/trending_request.dart'; 5 | 6 | @Singleton(as: TrendingRepository) 7 | class TrendingRepositoryImpl implements TrendingRepository { 8 | final MoviesShowsDataSource moviesShowsDataSource; 9 | 10 | TrendingRepositoryImpl(this.moviesShowsDataSource); 11 | 12 | @override 13 | Future getTrendingMovies(String type) { 14 | return moviesShowsDataSource 15 | .getTrending(TrendingRequest(type: type)); 16 | } 17 | 18 | @override 19 | Future getTrendingShows(String type) { 20 | return moviesShowsDataSource 21 | .getTrending(TrendingRequest(type: type)); 22 | } 23 | 24 | @override 25 | Future getTrendingPeople(String type) { 26 | return moviesShowsDataSource 27 | .getTrendingPeople(TrendingRequest(type: type)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /data/lib/repository/video_repository_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/video_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | import 'package:remote/datasource/movies_shows_data_source.dart'; 4 | import 'package:remote/model/trailer_request.dart'; 5 | 6 | @Singleton(as: VideoRepository) 7 | class VideoRepositoryImpl extends VideoRepository { 8 | final MoviesShowsDataSource moviesShowsDataSource; 9 | 10 | VideoRepositoryImpl(this.moviesShowsDataSource); 11 | 12 | @override 13 | Future getMovieTrailer(String type, double id) { 14 | return moviesShowsDataSource.getTrailer(TrailerRequest(type, id)); 15 | } 16 | 17 | @override 18 | Future getShowTrailer(String type, double id) { 19 | return moviesShowsDataSource.getTrailer(TrailerRequest(type, id)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /data/pubspec.yaml: -------------------------------------------------------------------------------- 1 | publish_to: none 2 | name: data 3 | description: A new flutter module project. 4 | 5 | # The following defines the version and build number for your application. 6 | # A version number is three numbers separated by dots, like 1.2.43 7 | # followed by an optional build number separated by a +. 8 | # Both the version and the builder number may be overridden in flutter 9 | # build by specifying --build-name and --build-number, respectively. 10 | # In Android, build-name is used as versionName while build-number used as versionCode. 11 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 12 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 13 | # Read more about iOS versioning at 14 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 15 | # 16 | # This version is used _only_ for the Runner app, which is used if you just do 17 | # a `flutter run` or a `flutter make-host-app-editable`. It has no impact 18 | # on any other native host app that you embed your Flutter project into. 19 | version: 1.0.0+1 20 | 21 | environment: 22 | sdk: ">=2.12.0 <3.0.0" 23 | 24 | dependencies: 25 | flutter: 26 | sdk: flutter 27 | 28 | # The following adds the Cupertino Icons font to your application. 29 | # Use with the CupertinoIcons class for iOS style icons. 30 | cupertino_icons: ^1.0.0 31 | injectable: ^1.2.2 32 | get_it: ^6.0.0 33 | 34 | domain: 35 | path: ../domain 36 | 37 | remote: 38 | path: ../remote 39 | 40 | dev_dependencies: 41 | flutter_test: 42 | sdk: flutter 43 | injectable_generator: 1.2.2 44 | build_runner: 1.12.2 45 | 46 | # For information on the generic Dart part of this file, see the 47 | # following page: https://dart.dev/tools/pub/pubspec 48 | 49 | flutter: 50 | # The following line ensures that the Material Icons font is 51 | # included with your application, so that you can use the icons in 52 | # the material Icons class. 53 | uses-material-design: true 54 | 55 | # To add Flutter specific assets to your application, add an assets section, 56 | # like this: 57 | # assets: 58 | # - images/a_dot_burr.jpeg 59 | # - images/a_dot_ham.jpeg 60 | 61 | # An image asset can refer to one or more resolution-specific "variants", see 62 | # https://flutter.dev/assets-and-images/#resolution-aware. 63 | 64 | # For details regarding adding assets from package dependencies, see 65 | # https://flutter.dev/assets-and-images/#from-packages 66 | 67 | # To add Flutter specific custom fonts to your application, add a fonts 68 | # section here, in this "flutter" section. Each entry in this list should 69 | # have a "family" key with the font family name, and a "fonts" key with a 70 | # list giving the asset and other descriptors for the font. For 71 | # example: 72 | # fonts: 73 | # - family: Schyler 74 | # fonts: 75 | # - asset: fonts/Schyler-Regular.ttf 76 | # - asset: fonts/Schyler-Italic.ttf 77 | # style: italic 78 | # - family: Trajan Pro 79 | # fonts: 80 | # - asset: fonts/TrajanPro.ttf 81 | # - asset: fonts/TrajanPro_Bold.ttf 82 | # weight: 700 83 | # 84 | # For details regarding fonts from package dependencies, 85 | # see https://flutter.dev/custom-fonts/#from-packages 86 | 87 | 88 | # This section identifies your Flutter project as a module meant for 89 | # embedding in a native host app. These identifiers should _not_ ordinarily 90 | # be changed after generation - they are used to ensure that the tooling can 91 | # maintain consistency when adding or modifying assets and plugins. 92 | # They also do not have any bearing on your native host application's 93 | # identifiers, which may be completely independent or the same as these. 94 | module: 95 | androidX: true 96 | androidPackage: com.ruben.funbox.data 97 | iosBundleIdentifier: com.ruben.funbox.data 98 | -------------------------------------------------------------------------------- /domain/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | .idea/ 8 | .vagrant/ 9 | .sconsign.dblite 10 | .svn/ 11 | 12 | *.swp 13 | profile 14 | 15 | DerivedData/ 16 | 17 | .generated/ 18 | 19 | *.pbxuser 20 | *.mode1v3 21 | *.mode2v3 22 | *.perspectivev3 23 | 24 | !default.pbxuser 25 | !default.mode1v3 26 | !default.mode2v3 27 | !default.perspectivev3 28 | 29 | xcuserdata 30 | 31 | *.moved-aside 32 | 33 | *.pyc 34 | *sync/ 35 | Icon? 36 | .tags* 37 | 38 | build/ 39 | .android/ 40 | .ios/ 41 | .flutter-plugins 42 | .flutter-plugins-dependencies 43 | 44 | # Symbolication related 45 | app.*.symbols 46 | 47 | # Obfuscation related 48 | app.*.map.json 49 | -------------------------------------------------------------------------------- /domain/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6 8 | channel: stable 9 | 10 | project_type: module 11 | -------------------------------------------------------------------------------- /domain/README.md: -------------------------------------------------------------------------------- 1 | # domain 2 | 3 | A new flutter module project. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.dev/). 9 | 10 | For instructions integrating Flutter modules to your existing applications, 11 | see the [add-to-app documentation](https://flutter.dev/docs/development/add-to-app). 12 | -------------------------------------------------------------------------------- /domain/domain.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /domain/domain_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /domain/lib/di/di.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/di/di.config.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @InjectableInit( 5 | initializerName: r'$initDomainGetIt' 6 | ) 7 | Future configureDomainInjection(final getIt) async => $initDomainGetIt(getIt); -------------------------------------------------------------------------------- /domain/lib/model/cast_record.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | 3 | class CastRecord { 4 | int? id; 5 | List? cast; 6 | List? crew; 7 | 8 | CastRecord({this.id, this.cast, this.crew}); 9 | 10 | CastRecord.fromJson(Map json) { 11 | id = json['id']; 12 | if (json['cast'] != null) { 13 | cast = []; 14 | try { 15 | json['cast'].forEach((v) { 16 | cast?.add(new Cast.fromJson(v)); 17 | }); 18 | } catch (_) { 19 | debugPrint('Data inconsistency'); 20 | } 21 | } 22 | if (json['crew'] != null) { 23 | crew = []; 24 | try { 25 | json['crew'].forEach((v) { 26 | crew?.add(new Crew.fromJson(v)); 27 | }); 28 | } catch (_) { 29 | debugPrint('Data inconsistency'); 30 | } 31 | } 32 | } 33 | 34 | Map toJson() { 35 | final Map data = new Map(); 36 | data['id'] = this.id; 37 | if (this.cast != null) { 38 | data['cast'] = this.cast!.map((v) => v.toJson()).toList(); 39 | } 40 | if (this.crew != null) { 41 | data['crew'] = this.crew!.map((v) => v.toJson()).toList(); 42 | } 43 | return data; 44 | } 45 | } 46 | 47 | class Cast { 48 | bool? adult; 49 | int? gender; 50 | int? id; 51 | String? knownForDepartment; 52 | String? name; 53 | String? originalName; 54 | double? popularity; 55 | String? profilePath; 56 | int? castId; 57 | String? character; 58 | String? creditId; 59 | int? order; 60 | 61 | Cast( 62 | {this.adult, 63 | this.gender, 64 | this.id, 65 | this.knownForDepartment, 66 | this.name, 67 | this.originalName, 68 | this.popularity, 69 | this.profilePath, 70 | this.castId, 71 | this.character, 72 | this.creditId, 73 | this.order}); 74 | 75 | Cast.fromJson(Map json) { 76 | adult = json['adult']; 77 | gender = json['gender']; 78 | id = json['id']; 79 | knownForDepartment = json['known_for_department']; 80 | name = json['name']; 81 | originalName = json['original_name']; 82 | popularity = json['popularity'].toDouble(); 83 | profilePath = json['profile_path']; 84 | castId = json['cast_id']; 85 | character = json['character']; 86 | creditId = json['credit_id']; 87 | order = json['order']; 88 | } 89 | 90 | Map toJson() { 91 | final Map data = new Map(); 92 | data['adult'] = this.adult; 93 | data['gender'] = this.gender; 94 | data['id'] = this.id; 95 | data['known_for_department'] = this.knownForDepartment; 96 | data['name'] = this.name; 97 | data['original_name'] = this.originalName; 98 | data['popularity'] = this.popularity; 99 | data['profile_path'] = this.profilePath; 100 | data['cast_id'] = this.castId; 101 | data['character'] = this.character; 102 | data['credit_id'] = this.creditId; 103 | data['order'] = this.order; 104 | return data; 105 | } 106 | } 107 | 108 | class Crew { 109 | bool? adult; 110 | int? gender; 111 | int? id; 112 | String? knownForDepartment; 113 | String? name; 114 | String? originalName; 115 | double? popularity; 116 | String? profilePath; 117 | String? creditId; 118 | String? department; 119 | String? job; 120 | 121 | Crew( 122 | {this.adult, 123 | this.gender, 124 | this.id, 125 | this.knownForDepartment, 126 | this.name, 127 | this.originalName, 128 | this.popularity, 129 | this.profilePath, 130 | this.creditId, 131 | this.department, 132 | this.job}); 133 | 134 | Crew.fromJson(Map json) { 135 | adult = json['adult']; 136 | gender = json['gender']; 137 | id = json['id']; 138 | knownForDepartment = json['known_for_department']; 139 | name = json['name']; 140 | originalName = json['original_name']; 141 | popularity = json['popularity'].toDouble(); 142 | profilePath = json['profile_path']; 143 | creditId = json['credit_id']; 144 | department = json['department']; 145 | job = json['job']; 146 | } 147 | 148 | Map toJson() { 149 | final Map data = new Map(); 150 | data['adult'] = this.adult; 151 | data['gender'] = this.gender; 152 | data['id'] = this.id; 153 | data['known_for_department'] = this.knownForDepartment; 154 | data['name'] = this.name; 155 | data['original_name'] = this.originalName; 156 | data['popularity'] = this.popularity; 157 | data['profile_path'] = this.profilePath; 158 | data['credit_id'] = this.creditId; 159 | data['department'] = this.department; 160 | data['job'] = this.job; 161 | return data; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /domain/lib/model/config_record.dart: -------------------------------------------------------------------------------- 1 | class ConfigRecord { 2 | Images? images; 3 | List? changeKeys; 4 | 5 | ConfigRecord({this.images, this.changeKeys}); 6 | 7 | ConfigRecord.fromJson(Map json) { 8 | images = 9 | json['images'] != null ? new Images.fromJson(json['images']) : null; 10 | changeKeys = json['change_keys'].cast(); 11 | } 12 | 13 | Map toJson() { 14 | final Map data = new Map(); 15 | if (this.images != null) { 16 | data['images'] = this.images!.toJson(); 17 | } 18 | data['change_keys'] = this.changeKeys; 19 | return data; 20 | } 21 | } 22 | 23 | class Images { 24 | String? baseUrl; 25 | String? secureBaseUrl; 26 | List? backdropSizes; 27 | List? logoSizes; 28 | List? posterSizes; 29 | List? profileSizes; 30 | List? stillSizes; 31 | 32 | Images( 33 | {this.baseUrl, 34 | this.secureBaseUrl, 35 | this.backdropSizes, 36 | this.logoSizes, 37 | this.posterSizes, 38 | this.profileSizes, 39 | this.stillSizes}); 40 | 41 | Images.fromJson(Map json) { 42 | baseUrl = json['base_url']; 43 | secureBaseUrl = json['secure_base_url']; 44 | backdropSizes = json['backdrop_sizes'].cast(); 45 | logoSizes = json['logo_sizes'].cast(); 46 | posterSizes = json['poster_sizes'].cast(); 47 | profileSizes = json['profile_sizes'].cast(); 48 | stillSizes = json['still_sizes'].cast(); 49 | } 50 | 51 | Map toJson() { 52 | final Map data = new Map(); 53 | data['base_url'] = this.baseUrl; 54 | data['secure_base_url'] = this.secureBaseUrl; 55 | data['backdrop_sizes'] = this.backdropSizes; 56 | data['logo_sizes'] = this.logoSizes; 57 | data['poster_sizes'] = this.posterSizes; 58 | data['profile_sizes'] = this.profileSizes; 59 | data['still_sizes'] = this.stillSizes; 60 | return data; 61 | } 62 | } -------------------------------------------------------------------------------- /domain/lib/model/movie_show_genres_record.dart: -------------------------------------------------------------------------------- 1 | class MovieShowGenresRecord { 2 | List? genres; 3 | 4 | MovieShowGenresRecord({this.genres}); 5 | 6 | MovieShowGenresRecord.fromJson(Map json) { 7 | if (json['genres'] != null) { 8 | genres = []; 9 | json['genres'].forEach((v) { 10 | genres?.add(new Genres.fromJson(v)); 11 | }); 12 | } 13 | } 14 | 15 | Map toJson() { 16 | final Map data = new Map(); 17 | if (this.genres != null) { 18 | data['genres'] = this.genres!.map((v) => v.toJson()).toList(); 19 | } 20 | return data; 21 | } 22 | } 23 | 24 | class Genres { 25 | int? id; 26 | String? name; 27 | 28 | Genres({this.id, this.name}); 29 | 30 | Genres.fromJson(Map json) { 31 | id = json['id']; 32 | name = json['name']; 33 | } 34 | 35 | Map toJson() { 36 | final Map data = new Map(); 37 | data['id'] = this.id; 38 | data['name'] = this.name; 39 | return data; 40 | } 41 | } -------------------------------------------------------------------------------- /domain/lib/model/movies_shows_record.dart: -------------------------------------------------------------------------------- 1 | class MoviesShowsRecord { 2 | int? page; 3 | List? results; 4 | int? totalPages; 5 | int? totalResults; 6 | 7 | MoviesShowsRecord({this.page, this.results, this.totalPages, this.totalResults}); 8 | 9 | MoviesShowsRecord.fromJson(Map json) { 10 | page = json['page']; 11 | if (json['results'] != null) { 12 | results = []; 13 | json['results'].forEach((v) { 14 | results?.add(new Results.fromJson(v)); 15 | }); 16 | } 17 | totalPages = json['total_pages']; 18 | totalResults = json['total_results']; 19 | } 20 | 21 | Map toJson() { 22 | final Map data = new Map(); 23 | data['page'] = this.page; 24 | if (this.results != null) { 25 | data['results'] = this.results?.map((v) => v.toJson()).toList(); 26 | } 27 | data['total_pages'] = this.totalPages; 28 | data['total_results'] = this.totalResults; 29 | return data; 30 | } 31 | } 32 | 33 | class Results { 34 | String? title; 35 | String? originalLanguage; 36 | String? originalTitle; 37 | String? posterPath; 38 | bool? video; 39 | double? voteAverage; 40 | String? overview; 41 | int? id; 42 | int? voteCount; 43 | bool? adult; 44 | String? backdropPath; 45 | String? releaseDate; 46 | List? genreIds; 47 | double? popularity; 48 | String? mediaType; 49 | String? firstAirDate; 50 | List? originCountry; 51 | String? name; 52 | String? originalName; 53 | 54 | Results( 55 | {this.title, 56 | this.originalLanguage, 57 | this.originalTitle, 58 | this.posterPath, 59 | this.video, 60 | this.voteAverage, 61 | this.overview, 62 | this.id, 63 | this.voteCount, 64 | this.adult, 65 | this.backdropPath, 66 | this.releaseDate, 67 | this.genreIds, 68 | this.popularity, 69 | this.mediaType, 70 | this.firstAirDate, 71 | this.originCountry, 72 | this.name, 73 | this.originalName}); 74 | 75 | Results.fromJson(Map json) { 76 | title = json['title']; 77 | originalLanguage = json['original_language']; 78 | originalTitle = json['original_title']; 79 | if(json['poster_path'] != null) { 80 | posterPath = json['poster_path']; 81 | } 82 | video = json['video']; 83 | if(json['vote_average'] != null) { 84 | voteAverage = json['vote_average'].toDouble(); 85 | } 86 | overview = json['overview']; 87 | id = json['id']; 88 | voteCount = json['vote_count']; 89 | adult = json['adult']; 90 | if(json['backdrop_path'] != null) { 91 | backdropPath = json['backdrop_path']; 92 | } 93 | releaseDate = json['release_date']; 94 | if(json['genre_ids'] != null) { 95 | genreIds = json['genre_ids'].cast(); 96 | } 97 | popularity = json['popularity'].toDouble(); 98 | if (json['media_type'] != null) { 99 | mediaType = json['media_type']; 100 | } 101 | if (json['first_air_date'] != null) { 102 | firstAirDate = json['first_air_date']; 103 | } 104 | if (json['origin_country'] != null) { 105 | originCountry = json['origin_country'].cast(); 106 | } 107 | if (json['name'] != null) { 108 | name = json['name']; 109 | } 110 | if (json['original_name'] != null) { 111 | originalName = json['original_name']; 112 | } 113 | } 114 | 115 | Map toJson() { 116 | final Map data = new Map(); 117 | data['title'] = this.title; 118 | data['original_language'] = this.originalLanguage; 119 | data['original_title'] = this.originalTitle; 120 | data['poster_path'] = this.posterPath; 121 | data['video'] = this.video; 122 | data['vote_average'] = this.voteAverage; 123 | data['overview'] = this.overview; 124 | data['id'] = this.id; 125 | data['vote_count'] = this.voteCount; 126 | data['adult'] = this.adult; 127 | data['backdrop_path'] = this.backdropPath; 128 | data['release_date'] = this.releaseDate; 129 | data['genre_ids'] = this.genreIds; 130 | data['popularity'] = this.popularity; 131 | data['media_type'] = this.mediaType; 132 | data['first_air_date'] = this.firstAirDate; 133 | data['origin_country'] = this.originCountry; 134 | data['name'] = this.name; 135 | data['original_name'] = this.originalName; 136 | return data; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /domain/lib/model/person_info_record.dart: -------------------------------------------------------------------------------- 1 | class PersonInfoRecord { 2 | bool? adult; 3 | List? alsoKnownAs; 4 | String? biography; 5 | String? birthday; 6 | String? deathday; 7 | int? gender; 8 | String? homepage; 9 | int? id; 10 | String? imdbId; 11 | String? knownForDepartment; 12 | String? name; 13 | String? placeOfBirth; 14 | double? popularity; 15 | String? profilePath; 16 | 17 | PersonInfoRecord( 18 | {this.adult, 19 | this.alsoKnownAs, 20 | this.biography, 21 | this.birthday, 22 | this.deathday, 23 | this.gender, 24 | this.homepage, 25 | this.id, 26 | this.imdbId, 27 | this.knownForDepartment, 28 | this.name, 29 | this.placeOfBirth, 30 | this.popularity, 31 | this.profilePath}); 32 | 33 | PersonInfoRecord.fromJson(Map json) { 34 | adult = json['adult']; 35 | alsoKnownAs = json['also_known_as'].cast(); 36 | biography = json['biography']; 37 | birthday = json['birthday']; 38 | deathday = json['deathday']; 39 | gender = json['gender']; 40 | homepage = json['homepage']; 41 | id = json['id']; 42 | imdbId = json['imdb_id']; 43 | knownForDepartment = json['known_for_department']; 44 | name = json['name']; 45 | placeOfBirth = json['place_of_birth']; 46 | popularity = json['popularity'].toDouble(); 47 | profilePath = json['profile_path']; 48 | } 49 | 50 | Map toJson() { 51 | final Map data = new Map(); 52 | data['adult'] = this.adult; 53 | data['also_known_as'] = this.alsoKnownAs; 54 | data['biography'] = this.biography; 55 | data['birthday'] = this.birthday; 56 | data['deathday'] = this.deathday; 57 | data['gender'] = this.gender; 58 | data['homepage'] = this.homepage; 59 | data['id'] = this.id; 60 | data['imdb_id'] = this.imdbId; 61 | data['known_for_department'] = this.knownForDepartment; 62 | data['name'] = this.name; 63 | data['place_of_birth'] = this.placeOfBirth; 64 | data['popularity'] = this.popularity; 65 | data['profile_path'] = this.profilePath; 66 | return data; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /domain/lib/model/trailer_record.dart: -------------------------------------------------------------------------------- 1 | class TrailerRecord { 2 | int? id; 3 | List? results; 4 | 5 | TrailerRecord({this.id, this.results}); 6 | 7 | TrailerRecord.fromJson(Map json) { 8 | id = json['id']; 9 | if (json['results'] != null) { 10 | results = []; 11 | json['results'].forEach((v) { 12 | results?.add(new Results.fromJson(v)); 13 | }); 14 | } 15 | } 16 | 17 | Map toJson() { 18 | final Map data = new Map(); 19 | data['id'] = this.id; 20 | if (this.results != null) { 21 | data['results'] = this.results!.map((v) => v.toJson()).toList(); 22 | } 23 | return data; 24 | } 25 | } 26 | 27 | class Results { 28 | String? id; 29 | String? iso6391; 30 | String? iso31661; 31 | String? key; 32 | String? name; 33 | String? site; 34 | int? size; 35 | String? type; 36 | 37 | Results( 38 | {this.id, 39 | this.iso6391, 40 | this.iso31661, 41 | this.key, 42 | this.name, 43 | this.site, 44 | this.size, 45 | this.type}); 46 | 47 | Results.fromJson(Map json) { 48 | id = json['id']; 49 | iso6391 = json['iso_639_1']; 50 | iso31661 = json['iso_3166_1']; 51 | key = json['key']; 52 | name = json['name']; 53 | site = json['site']; 54 | size = json['size']; 55 | type = json['type']; 56 | } 57 | 58 | Map toJson() { 59 | final Map data = new Map(); 60 | data['id'] = this.id; 61 | data['iso_639_1'] = this.iso6391; 62 | data['iso_3166_1'] = this.iso31661; 63 | data['key'] = this.key; 64 | data['name'] = this.name; 65 | data['site'] = this.site; 66 | data['size'] = this.size; 67 | data['type'] = this.type; 68 | return data; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /domain/lib/repository/cast_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class CastRepository { 2 | 3 | Future getMovieCast(String type, double id); 4 | Future getShowCast(String type, double id); 5 | 6 | } -------------------------------------------------------------------------------- /domain/lib/repository/config_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class ConfigRepository { 2 | 3 | Future getConfig(); 4 | 5 | } -------------------------------------------------------------------------------- /domain/lib/repository/details_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class DetailsRepository { 2 | 3 | Future getMovieDetails(String type, double id); 4 | Future getShowDetails(String type, double id); 5 | } -------------------------------------------------------------------------------- /domain/lib/repository/filter_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class FilterRepository { 2 | Future getGenres(String type); 3 | } -------------------------------------------------------------------------------- /domain/lib/repository/movies_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class MoviesRepository { 2 | 3 | Future getCurrentPlayingMovies(int page); 4 | Future getPopularMovies(String type, int page); 5 | Future getLatestMovies(String type, int page); 6 | Future getTopRatedMovies(String type, int page); 7 | Future getUpcomingMovies(int page); 8 | Future getMoviesByGenre(String type, int genreId, int page); 9 | 10 | } -------------------------------------------------------------------------------- /domain/lib/repository/person_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class PersonRepository { 2 | 3 | Future getPersonInfo(double id); 4 | Future getPersonCredits(double id); 5 | 6 | } -------------------------------------------------------------------------------- /domain/lib/repository/search_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class SearchRepository { 2 | Future searchMoviesShows(String searchTerm); 3 | } -------------------------------------------------------------------------------- /domain/lib/repository/shows_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class ShowsRepository { 2 | 3 | Future getCurrentPlayingShows(int page); 4 | Future getPopularShows(String type, int page); 5 | Future getLatestShows(String type, int page); 6 | Future getTopRatedShows(String type, int page); 7 | Future getAiringTodayShows(int page); 8 | Future getShowsByGenre(String type, int genreId, int page); 9 | 10 | } -------------------------------------------------------------------------------- /domain/lib/repository/trending_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class TrendingRepository { 2 | 3 | Future getTrendingMovies(String type); 4 | Future getTrendingShows(String type); 5 | Future getTrendingPeople(String type); 6 | 7 | } -------------------------------------------------------------------------------- /domain/lib/repository/video_repository.dart: -------------------------------------------------------------------------------- 1 | abstract class VideoRepository { 2 | 3 | Future getMovieTrailer(String type, double id); 4 | Future getShowTrailer(String type, double id); 5 | } -------------------------------------------------------------------------------- /domain/lib/usecase/cast/movie_cast_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/cast_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class MovieCastUseCase { 6 | final CastRepository repository; 7 | 8 | MovieCastUseCase(this.repository); 9 | 10 | Future getMovieCast({required String type, required double id}) { 11 | return repository.getMovieCast(type, id); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/cast/show_cast_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/cast_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class ShowCastUseCase { 6 | final CastRepository repository; 7 | 8 | ShowCastUseCase(this.repository); 9 | 10 | Future getShowCast({required String type, required double id}) { 11 | return repository.getShowCast(type, id); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/details/movie_details_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/details_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class MovieDetailsUseCase { 6 | final DetailsRepository repository; 7 | 8 | MovieDetailsUseCase(this.repository); 9 | 10 | Future getMovieDetails({required String type, required double id}) { 11 | return repository.getMovieDetails(type, id); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/details/show_details_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/details_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class ShowDetailsUseCase { 6 | 7 | final DetailsRepository repository; 8 | 9 | ShowDetailsUseCase(this.repository); 10 | 11 | Future getShowDetails({required String type, required double id}) { 12 | return repository.getShowDetails(type, id); 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /domain/lib/usecase/filter/movie_filter_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/filter_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class MovieFilterUseCase { 6 | final FilterRepository repository; 7 | 8 | MovieFilterUseCase(this.repository); 9 | 10 | Future getMovieGenres({required String type}) { 11 | return repository.getGenres(type); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/filter/show_filter_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/filter_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class ShowFilterUseCase { 6 | final FilterRepository repository; 7 | 8 | ShowFilterUseCase(this.repository); 9 | 10 | Future getShowGenres({required String type}) { 11 | return repository.getGenres(type); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/get_config_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/config_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class GetConfigUseCase { 6 | 7 | final ConfigRepository repository; 8 | 9 | GetConfigUseCase(this.repository); 10 | 11 | Future getConfig() async { 12 | return repository.getConfig(); 13 | } 14 | } -------------------------------------------------------------------------------- /domain/lib/usecase/movies/current_playing_movies_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/movies_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class CurrentPlayingMoviesUseCase { 6 | final MoviesRepository repository; 7 | 8 | CurrentPlayingMoviesUseCase(this.repository); 9 | 10 | Future getCurrentPlayingMovies({required int page}) { 11 | return repository.getCurrentPlayingMovies(page); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/movies/latest_movies_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/movies_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class LatestMoviesUseCase { 6 | final MoviesRepository repository; 7 | 8 | LatestMoviesUseCase(this.repository); 9 | 10 | Future getLatestMovies({required String type, required int page}) { 11 | return repository.getLatestMovies(type, page); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/movies/movies_by_genres_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/movies_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class MoviesByGenresUseCase { 6 | final MoviesRepository repository; 7 | 8 | MoviesByGenresUseCase(this.repository); 9 | 10 | Future getMoviesByGenre( 11 | {required String type, required int genreId, required int page}) { 12 | return repository.getMoviesByGenre(type, genreId, page); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /domain/lib/usecase/movies/popular_movies_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/movies_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class PopularMoviesUseCase { 6 | final MoviesRepository repository; 7 | 8 | PopularMoviesUseCase(this.repository); 9 | 10 | Future getPopularMovies({required String type, required int page}) { 11 | return repository.getPopularMovies(type, page); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/movies/top_rated_movies_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/movies_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class TopRatedMoviesUseCase { 6 | final MoviesRepository repository; 7 | 8 | TopRatedMoviesUseCase(this.repository); 9 | 10 | Future getTopRatedMovies({required String type, required int page}) { 11 | return repository.getTopRatedMovies(type, page); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/movies/upcoming_movies_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/movies_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class UpcomingMoviesUseCase { 6 | final MoviesRepository repository; 7 | 8 | UpcomingMoviesUseCase(this.repository); 9 | 10 | Future getUpcomingMovies({required int page}) { 11 | return repository.getUpcomingMovies(page); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/person/person_credits_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/person_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class PersonCreditsUseCase { 6 | final PersonRepository repository; 7 | 8 | PersonCreditsUseCase(this.repository); 9 | 10 | Future getPersonCredits({required double id}) { 11 | return repository.getPersonCredits(id); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/person/person_info_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/person_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class PersonInfoUseCase { 6 | final PersonRepository repository; 7 | 8 | PersonInfoUseCase(this.repository); 9 | 10 | Future getPersonIfo({required double id}) { 11 | return repository.getPersonInfo(id); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/search_movies_shows_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/search_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class SearchMoviesShowsUseCase { 6 | final SearchRepository repository; 7 | 8 | SearchMoviesShowsUseCase(this.repository); 9 | 10 | Future searchMoviesShows({required String searchTerm}) { 11 | return repository.searchMoviesShows(searchTerm); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/shows/airing_today_shows_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/shows_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class AiringTodayShowsUseCase { 6 | final ShowsRepository repository; 7 | 8 | AiringTodayShowsUseCase(this.repository); 9 | 10 | Future getAiringTodayShows({required int page}) { 11 | return repository.getAiringTodayShows(page); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/shows/current_playing_shows_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/shows_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class CurrentPlayingShowsUseCase { 6 | final ShowsRepository repository; 7 | 8 | CurrentPlayingShowsUseCase(this.repository); 9 | 10 | Future getCurrentPlayingShows({required int page}) { 11 | return repository.getCurrentPlayingShows(page); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/shows/latest_shows_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/shows_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class LatestShowsUseCase { 6 | final ShowsRepository repository; 7 | 8 | LatestShowsUseCase(this.repository); 9 | 10 | Future getLatestShows({required String type, required int page}) { 11 | return repository.getLatestShows(type, page); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/shows/popular_shows_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/shows_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class PopularShowsUseCase { 6 | final ShowsRepository repository; 7 | 8 | PopularShowsUseCase(this.repository); 9 | 10 | Future getPopularShows({required String type, required int page}) { 11 | return repository.getPopularShows(type, page); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/shows/shows_by_genres_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/shows_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class ShowsByGenresUseCase { 6 | final ShowsRepository repository; 7 | 8 | ShowsByGenresUseCase(this.repository); 9 | 10 | Future getShowsByGenres( 11 | {required String type, required int genreId, required int page}) { 12 | return repository.getShowsByGenre(type, genreId, page); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /domain/lib/usecase/shows/top_rated_shows_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/shows_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class TopRatedShowsUseCase { 6 | final ShowsRepository repository; 7 | 8 | TopRatedShowsUseCase(this.repository); 9 | 10 | Future getTopRatedShows({required String type, required int page}) { 11 | return repository.getTopRatedShows(type, page); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/trending/trending_movies_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/trending_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class TrendingMoviesUseCase { 6 | final TrendingRepository repository; 7 | 8 | TrendingMoviesUseCase(this.repository); 9 | 10 | Future getTrendingMovies({required String type}) async { 11 | return repository.getTrendingMovies(type); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/trending/trending_people_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/trending_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class TrendingPeopleUseCase { 6 | final TrendingRepository repository; 7 | 8 | TrendingPeopleUseCase(this.repository); 9 | 10 | Future getTrendingPeople({required String type}) { 11 | return repository.getTrendingPeople(type); 12 | } 13 | } -------------------------------------------------------------------------------- /domain/lib/usecase/trending/trending_shows_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/trending_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class TrendingShowsUseCase { 6 | 7 | final TrendingRepository repository; 8 | 9 | TrendingShowsUseCase(this.repository); 10 | 11 | Future getTrendingShows({required String type}) { 12 | return repository.getTrendingShows(type); 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /domain/lib/usecase/video/movie_trailer_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/video_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class MovieTrailerUseCase { 6 | final VideoRepository repository; 7 | 8 | MovieTrailerUseCase(this.repository); 9 | 10 | Future getMovieTrailer({required String type, required double id}) { 11 | return repository.getMovieTrailer(type, id); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/lib/usecase/video/show_trailer_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/repository/video_repository.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @injectable 5 | class ShowTrailerUseCase { 6 | final VideoRepository repository; 7 | 8 | ShowTrailerUseCase(this.repository); 9 | 10 | Future getShowTrailer({required String type, required double id}) { 11 | return repository.getShowTrailer(type, id); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /domain/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: domain 2 | description: A new flutter module project. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | # 15 | # This version is used _only_ for the Runner app, which is used if you just do 16 | # a `flutter run` or a `flutter make-host-app-editable`. It has no impact 17 | # on any other native host app that you embed your Flutter project into. 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | 27 | # The following adds the Cupertino Icons font to your application. 28 | # Use with the CupertinoIcons class for iOS style icons. 29 | cupertino_icons: ^1.0.0 30 | injectable: ^1.2.2 31 | get_it: ^6.0.0 32 | 33 | dev_dependencies: 34 | flutter_test: 35 | sdk: flutter 36 | injectable_generator: 1.2.2 37 | build_runner: 1.12.2 38 | 39 | # For information on the generic Dart part of this file, see the 40 | # following page: https://dart.dev/tools/pub/pubspec 41 | 42 | flutter: 43 | # The following line ensures that the Material Icons font is 44 | # included with your application, so that you can use the icons in 45 | # the material Icons class. 46 | uses-material-design: true 47 | 48 | # To add Flutter specific assets to your application, add an assets section, 49 | # like this: 50 | # assets: 51 | # - images/a_dot_burr.jpeg 52 | # - images/a_dot_ham.jpeg 53 | 54 | # An image asset can refer to one or more resolution-specific "variants", see 55 | # https://flutter.dev/assets-and-images/#resolution-aware. 56 | 57 | # For details regarding adding assets from package dependencies, see 58 | # https://flutter.dev/assets-and-images/#from-packages 59 | 60 | # To add Flutter specific custom fonts to your application, add a fonts 61 | # section here, in this "flutter" section. Each entry in this list should 62 | # have a "family" key with the font family name, and a "fonts" key with a 63 | # list giving the asset and other descriptors for the font. For 64 | # example: 65 | # fonts: 66 | # - family: Schyler 67 | # fonts: 68 | # - asset: fonts/Schyler-Regular.ttf 69 | # - asset: fonts/Schyler-Italic.ttf 70 | # style: italic 71 | # - family: Trajan Pro 72 | # fonts: 73 | # - asset: fonts/TrajanPro.ttf 74 | # - asset: fonts/TrajanPro_Bold.ttf 75 | # weight: 700 76 | # 77 | # For details regarding fonts from package dependencies, 78 | # see https://flutter.dev/custom-fonts/#from-packages 79 | 80 | 81 | # This section identifies your Flutter project as a module meant for 82 | # embedding in a native host app. These identifiers should _not_ ordinarily 83 | # be changed after generation - they are used to ensure that the tooling can 84 | # maintain consistency when adding or modifying assets and plugins. 85 | # They also do not have any bearing on your native host application's 86 | # identifiers, which may be completely independent or the same as these. 87 | module: 88 | androidX: true 89 | androidPackage: com.ruben.funbox.domain 90 | iosBundleIdentifier: com.ruben.funbox.domain 91 | -------------------------------------------------------------------------------- /fonts/ironclad.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/fonts/ironclad.ttf -------------------------------------------------------------------------------- /fonts/metropolis.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/fonts/metropolis.otf -------------------------------------------------------------------------------- /fun_box.iml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /images/error_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/images/error_image.png -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /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.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/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/LaunchScreen.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 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /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/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | fun_box 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/bloc/all/trending_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movies_shows_record.dart'; 2 | import 'package:domain/model/trending_people_record.dart'; 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | import 'package:domain/usecase/trending/trending_movies_use_case.dart'; 6 | import 'package:domain/usecase/trending/trending_people_use_case.dart'; 7 | import 'package:domain/usecase/trending/trending_shows_use_case.dart'; 8 | import 'package:fun_box/utils/app_constants.dart'; 9 | import 'package:injectable/injectable.dart'; 10 | import 'trending_event.dart'; 11 | import 'trending_state.dart'; 12 | 13 | @injectable 14 | class TrendingBloc extends Bloc { 15 | final TrendingMoviesUseCase trendingMoviesUseCase; 16 | final TrendingShowsUseCase trendingShowsUseCase; 17 | final TrendingPeopleUseCase trendingPeopleUseCase; 18 | 19 | TrendingBloc(this.trendingMoviesUseCase, this.trendingShowsUseCase, 20 | this.trendingPeopleUseCase) 21 | : super(InitialTrendingMoviesShowsState()); 22 | 23 | @override 24 | Stream mapEventToState(TrendingEvent event) async* { 25 | switch (event) { 26 | case TrendingEvent.movie: 27 | yield* _fetchTrendingMovies(AppConstants.movie); 28 | break; 29 | case TrendingEvent.tv: 30 | yield* _fetchTrendingShows(AppConstants.tvShow); 31 | break; 32 | case TrendingEvent.person: 33 | yield* _fetchTrendingPeople(AppConstants.person); 34 | break; 35 | default: 36 | break; 37 | } 38 | } 39 | 40 | Stream _fetchTrendingMovies(String type) async* { 41 | try { 42 | var response = await trendingMoviesUseCase.getTrendingMovies(type: type); 43 | yield SuccessTrendingMoviesState(MoviesShowsRecord.fromJson(response)); 44 | } catch (exception) { 45 | debugPrint('Error ${exception.toString()}'); 46 | yield ErrorMoviesShowsState(); 47 | } 48 | } 49 | 50 | Stream _fetchTrendingShows(String type) async* { 51 | try { 52 | var response = await trendingShowsUseCase.getTrendingShows(type: type); 53 | yield SuccessTrendingShowsState(MoviesShowsRecord.fromJson(response)); 54 | } catch (exception) { 55 | debugPrint('Error ${exception.toString()}'); 56 | yield ErrorMoviesShowsState(); 57 | } 58 | } 59 | 60 | Stream _fetchTrendingPeople(String type) async* { 61 | try { 62 | var response = await trendingPeopleUseCase.getTrendingPeople(type: type); 63 | yield SuccessTrendingPersonState(TrendingPeopleRecord.fromJson(response)); 64 | } catch (exception) { 65 | debugPrint('Error ${exception.toString()}'); 66 | yield ErrorMoviesShowsState(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/bloc/all/trending_event.dart: -------------------------------------------------------------------------------- 1 | enum TrendingEvent { 2 | movie, 3 | tv, 4 | person 5 | } 6 | 7 | -------------------------------------------------------------------------------- /lib/bloc/all/trending_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movies_shows_record.dart'; 2 | import 'package:domain/model/trending_people_record.dart'; 3 | 4 | abstract class TrendingState {} 5 | 6 | class InitialTrendingMoviesShowsState extends TrendingState {} 7 | 8 | class SuccessTrendingMoviesState extends TrendingState { 9 | final MoviesShowsRecord record; 10 | 11 | SuccessTrendingMoviesState(this.record); 12 | } 13 | 14 | class SuccessTrendingShowsState extends TrendingState { 15 | final MoviesShowsRecord record; 16 | 17 | SuccessTrendingShowsState(this.record); 18 | } 19 | 20 | class SuccessTrendingPersonState extends TrendingState { 21 | final TrendingPeopleRecord record; 22 | 23 | SuccessTrendingPersonState(this.record); 24 | } 25 | 26 | class ErrorMoviesShowsState extends TrendingState {} 27 | -------------------------------------------------------------------------------- /lib/bloc/cast/movie_show_cast_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/cast_record.dart'; 2 | import 'package:domain/usecase/cast/movie_cast_use_case.dart'; 3 | import 'package:domain/usecase/cast/show_cast_use_case.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:flutter_bloc/flutter_bloc.dart'; 6 | import 'package:fun_box/bloc/cast/movie_show_cast_event.dart'; 7 | import 'package:fun_box/bloc/cast/movie_show_cast_state.dart'; 8 | import 'package:fun_box/utils/app_constants.dart'; 9 | import 'package:injectable/injectable.dart'; 10 | 11 | @injectable 12 | class MovieShowCastBloc extends Bloc { 13 | final MovieCastUseCase movieCastUseCase; 14 | final ShowCastUseCase showCastUseCase; 15 | 16 | MovieShowCastBloc(this.movieCastUseCase, this.showCastUseCase) 17 | : super(InitialMovieShowCastState()); 18 | 19 | @override 20 | Stream mapEventToState(MovieShowCastEvent event) async* { 21 | switch (event.type) { 22 | case AppConstants.movie: 23 | yield* _fetchMovieCast(event.type, event.id); 24 | break; 25 | case AppConstants.tvShow: 26 | yield* _fetchShowCast(event.type, event.id); 27 | break; 28 | default: 29 | break; 30 | } 31 | } 32 | 33 | Stream _fetchMovieCast(String type, double id) async* { 34 | try { 35 | var response = await movieCastUseCase.getMovieCast(type: type, id: id); 36 | yield SuccessMovieShowCastState(CastRecord.fromJson(response)); 37 | } catch (exception) { 38 | debugPrint('Error ${exception.toString()}'); 39 | yield ErrorMovieShowCastState(); 40 | } 41 | } 42 | 43 | Stream _fetchShowCast(String type, double id) async* { 44 | try { 45 | var response = await showCastUseCase.getShowCast(type: type, id: id); 46 | yield SuccessMovieShowCastState(CastRecord.fromJson(response)); 47 | } catch (exception) { 48 | debugPrint('Error ${exception.toString()}'); 49 | yield ErrorMovieShowCastState(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/bloc/cast/movie_show_cast_event.dart: -------------------------------------------------------------------------------- 1 | class MovieShowCastEvent { 2 | final String type; 3 | final double id; 4 | 5 | MovieShowCastEvent({required this.type, required this.id}); 6 | } 7 | -------------------------------------------------------------------------------- /lib/bloc/cast/movie_show_cast_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/cast_record.dart'; 2 | 3 | abstract class MovieShowCastState {} 4 | 5 | class InitialMovieShowCastState extends MovieShowCastState {} 6 | 7 | class SuccessMovieShowCastState extends MovieShowCastState { 8 | final CastRecord record; 9 | 10 | SuccessMovieShowCastState(this.record); 11 | } 12 | 13 | class ErrorMovieShowCastState extends MovieShowCastState {} 14 | -------------------------------------------------------------------------------- /lib/bloc/details/movie_show_details_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movie_details_record.dart'; 2 | import 'package:domain/model/show_details_record.dart'; 3 | import 'package:domain/usecase/details/movie_details_use_case.dart'; 4 | import 'package:domain/usecase/details/show_details_use_case.dart'; 5 | import 'package:flutter/cupertino.dart'; 6 | import 'package:flutter_bloc/flutter_bloc.dart'; 7 | import 'package:fun_box/bloc/details/movie_show_details_event.dart'; 8 | import 'package:fun_box/bloc/details/movie_show_details_state.dart'; 9 | import 'package:fun_box/utils/app_constants.dart'; 10 | import 'package:injectable/injectable.dart'; 11 | 12 | @injectable 13 | class MovieShowDetailsBloc 14 | extends Bloc { 15 | final MovieDetailsUseCase movieDetailsUseCase; 16 | final ShowDetailsUseCase showDetailsUseCase; 17 | 18 | MovieShowDetailsBloc(this.movieDetailsUseCase, this.showDetailsUseCase) 19 | : super(InitialMovieShowDetailsState()); 20 | 21 | @override 22 | Stream mapEventToState( 23 | MovieShowDetailsEvent event) async* { 24 | switch (event.type) { 25 | case AppConstants.movie: 26 | yield* _fetchMovieDetail(event.type, event.id); 27 | break; 28 | case AppConstants.tvShow: 29 | yield* _fetchShowDetail(event.type, event.id); 30 | break; 31 | default: 32 | break; 33 | } 34 | } 35 | 36 | Stream _fetchMovieDetail( 37 | String type, double id) async* { 38 | try { 39 | var response = await movieDetailsUseCase.getMovieDetails(type: type, id: id); 40 | yield SuccessMovieDetailsState(MovieDetailsRecord.fromJson(response)); 41 | } catch (exception) { 42 | debugPrint('Error ${exception.toString()}'); 43 | yield ErrorMovieShowDetailsState(); 44 | } 45 | } 46 | 47 | Stream _fetchShowDetail( 48 | String type, double id) async* { 49 | try { 50 | var response = await showDetailsUseCase.getShowDetails(type: type, id: id); 51 | yield SuccessShowDetailsState(ShowDetailsRecord.fromJson(response)); 52 | } catch (exception) { 53 | debugPrint('Error ${exception.toString()}'); 54 | yield ErrorMovieShowDetailsState(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/bloc/details/movie_show_details_event.dart: -------------------------------------------------------------------------------- 1 | class MovieShowDetailsEvent { 2 | final String type; 3 | final double id; 4 | 5 | MovieShowDetailsEvent({required this.type, required this.id}); 6 | } 7 | -------------------------------------------------------------------------------- /lib/bloc/details/movie_show_details_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movie_details_record.dart'; 2 | import 'package:domain/model/show_details_record.dart'; 3 | 4 | abstract class MovieShowDetailsState {} 5 | 6 | class InitialMovieShowDetailsState extends MovieShowDetailsState {} 7 | 8 | class SuccessMovieDetailsState extends MovieShowDetailsState { 9 | final MovieDetailsRecord record; 10 | 11 | SuccessMovieDetailsState(this.record); 12 | } 13 | 14 | class SuccessShowDetailsState extends MovieShowDetailsState { 15 | final ShowDetailsRecord record; 16 | 17 | SuccessShowDetailsState(this.record); 18 | } 19 | 20 | class ErrorMovieShowDetailsState extends MovieShowDetailsState {} 21 | -------------------------------------------------------------------------------- /lib/bloc/filter/movies_shows_filter_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movie_show_genres_record.dart'; 2 | import 'package:domain/usecase/filter/movie_filter_use_case.dart'; 3 | import 'package:domain/usecase/filter/show_filter_use_case.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:flutter_bloc/flutter_bloc.dart'; 6 | import 'package:fun_box/bloc/filter/movies_shows_filter_event.dart'; 7 | import 'package:fun_box/bloc/filter/movies_shows_filter_state.dart'; 8 | import 'package:fun_box/utils/app_constants.dart'; 9 | import 'package:injectable/injectable.dart'; 10 | 11 | @injectable 12 | class MoviesShowsFilterBloc 13 | extends Bloc { 14 | final MovieFilterUseCase movieFilterUseCase; 15 | final ShowFilterUseCase showFilterUseCase; 16 | 17 | MoviesShowsFilterBloc(this.movieFilterUseCase, this.showFilterUseCase) 18 | : super(InitialMoviesShowsFilterState()); 19 | 20 | @override 21 | Stream mapEventToState( 22 | MoviesShowsFilterEvent event) async* { 23 | switch (event.type) { 24 | case AppConstants.movie: 25 | yield* _fetchMovieFilters(event.type); 26 | break; 27 | case AppConstants.tvShow: 28 | yield* _fetchShowFilters(event.type); 29 | break; 30 | default: 31 | break; 32 | } 33 | } 34 | 35 | Stream _fetchMovieFilters(String type) async* { 36 | try { 37 | var response = await movieFilterUseCase.getMovieGenres(type: type); 38 | yield SuccessMoviesShowsFilterState( 39 | MovieShowGenresRecord.fromJson(response)); 40 | } catch (exception) { 41 | debugPrint('Error ${exception.toString()}'); 42 | yield ErrorMoviesShowsFilterState(); 43 | } 44 | } 45 | 46 | Stream _fetchShowFilters(String type) async* { 47 | try { 48 | var response = await showFilterUseCase.getShowGenres(type: type); 49 | yield SuccessMoviesShowsFilterState( 50 | MovieShowGenresRecord.fromJson(response)); 51 | } catch (exception) { 52 | debugPrint('Error ${exception.toString()}'); 53 | yield ErrorMoviesShowsFilterState(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/bloc/filter/movies_shows_filter_event.dart: -------------------------------------------------------------------------------- 1 | class MoviesShowsFilterEvent { 2 | final String type; 3 | 4 | MoviesShowsFilterEvent({required this.type}); 5 | } 6 | -------------------------------------------------------------------------------- /lib/bloc/filter/movies_shows_filter_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movie_show_genres_record.dart'; 2 | 3 | abstract class MoviesShowsFilterState {} 4 | 5 | class InitialMoviesShowsFilterState extends MoviesShowsFilterState {} 6 | 7 | class SuccessMoviesShowsFilterState extends MoviesShowsFilterState { 8 | final MovieShowGenresRecord record; 9 | 10 | SuccessMoviesShowsFilterState(this.record); 11 | } 12 | 13 | class ErrorMoviesShowsFilterState extends MoviesShowsFilterState {} 14 | -------------------------------------------------------------------------------- /lib/bloc/movieshow/movies_shows_event.dart: -------------------------------------------------------------------------------- 1 | class MoviesShowsEvent { 2 | final String type; 3 | final String event; 4 | final int page; 5 | 6 | MoviesShowsEvent( 7 | {required this.type, required this.event, required this.page}); 8 | } 9 | -------------------------------------------------------------------------------- /lib/bloc/movieshow/movies_shows_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movies_shows_record.dart'; 2 | 3 | abstract class MoviesShowsState {} 4 | 5 | class InitialMoviesShowsState extends MoviesShowsState {} 6 | 7 | class SuccessMoviesShowsState extends MoviesShowsState { 8 | final MoviesShowsRecord record; 9 | 10 | SuccessMoviesShowsState(this.record); 11 | } 12 | 13 | class ErrorMoviesShowsState extends MoviesShowsState {} 14 | -------------------------------------------------------------------------------- /lib/bloc/person/person_details_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/person_credits_record.dart'; 2 | import 'package:domain/model/person_info_record.dart'; 3 | import 'package:domain/usecase/person/person_credits_use_case.dart'; 4 | import 'package:domain/usecase/person/person_info_use_case.dart'; 5 | import 'package:flutter/cupertino.dart'; 6 | import 'package:flutter_bloc/flutter_bloc.dart'; 7 | import 'package:fun_box/bloc/person/person_details_event.dart'; 8 | import 'package:fun_box/bloc/person/person_details_state.dart'; 9 | import 'package:fun_box/utils/app_constants.dart'; 10 | import 'package:injectable/injectable.dart'; 11 | 12 | @injectable 13 | class PersonDetailsBloc extends Bloc { 14 | final PersonInfoUseCase personInfoUseCase; 15 | final PersonCreditsUseCase personCreditsUseCase; 16 | 17 | PersonDetailsBloc(this.personInfoUseCase, this.personCreditsUseCase) 18 | : super(InitialPersonDetailsState()); 19 | 20 | @override 21 | Stream mapEventToState(PersonDetailsEvent event) async* { 22 | switch (event.type) { 23 | case AppConstants.personalInfo: 24 | yield* _fetchPersonalInfo(event.id); 25 | break; 26 | case AppConstants.credits: 27 | yield* _fetchCredits(event.id); 28 | break; 29 | default: 30 | break; 31 | } 32 | } 33 | 34 | Stream _fetchPersonalInfo(double id) async* { 35 | try { 36 | var response = await personInfoUseCase.getPersonIfo(id: id); 37 | yield SuccessPersonInfoState(PersonInfoRecord.fromJson(response)); 38 | } catch (exception) { 39 | debugPrint('Error ${exception.toString()}'); 40 | yield ErrorPersonDetailsState(); 41 | } 42 | } 43 | 44 | Stream _fetchCredits(double id) async* { 45 | try { 46 | var response = await personCreditsUseCase.getPersonCredits(id: id); 47 | yield SuccessPersonCreditsState(PersonCreditsRecord.fromJson(response)); 48 | } catch (exception) { 49 | debugPrint('Error ${exception.toString()}'); 50 | yield ErrorPersonDetailsState(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/bloc/person/person_details_event.dart: -------------------------------------------------------------------------------- 1 | class PersonDetailsEvent { 2 | final String type; 3 | final double id; 4 | 5 | PersonDetailsEvent({required this.type, required this.id}); 6 | } 7 | -------------------------------------------------------------------------------- /lib/bloc/person/person_details_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/person_credits_record.dart'; 2 | import 'package:domain/model/person_info_record.dart'; 3 | 4 | abstract class PersonDetailsState {} 5 | 6 | class InitialPersonDetailsState extends PersonDetailsState {} 7 | 8 | class SuccessPersonInfoState extends PersonDetailsState { 9 | final PersonInfoRecord record; 10 | 11 | SuccessPersonInfoState(this.record); 12 | } 13 | 14 | class SuccessPersonCreditsState extends PersonDetailsState { 15 | final PersonCreditsRecord record; 16 | 17 | SuccessPersonCreditsState(this.record); 18 | } 19 | 20 | class ErrorPersonDetailsState extends PersonDetailsState {} 21 | -------------------------------------------------------------------------------- /lib/bloc/search/movies_shows_search_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movies_shows_record.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:fun_box/bloc/search/movies_shows_search_event.dart'; 5 | import 'package:fun_box/bloc/search/movies_shows_search_state.dart'; 6 | import 'package:fun_box/utils/app_constants.dart'; 7 | import 'package:injectable/injectable.dart'; 8 | import 'package:domain/usecase/search_movies_shows_use_case.dart'; 9 | 10 | @injectable 11 | class MoviesShowsSearchBloc 12 | extends Bloc { 13 | final SearchMoviesShowsUseCase searchMoviesShowsUseCase; 14 | 15 | MoviesShowsSearchBloc(this.searchMoviesShowsUseCase) 16 | : super(InitialMoviesShowsSearchState()); 17 | 18 | @override 19 | Stream mapEventToState( 20 | MoviesShowsSearchEvent event) async* { 21 | switch (event.event) { 22 | case AppConstants.suggestions: 23 | yield* _fetchSuggestions(event.searchTerm); 24 | break; 25 | case AppConstants.progress: 26 | yield* _showProgress(); 27 | break; 28 | default: 29 | break; 30 | } 31 | } 32 | 33 | Stream _showProgress() async* { 34 | yield ProgressMoviesShowsSearchState(); 35 | } 36 | 37 | Stream _fetchSuggestions(String searchTerm) async* { 38 | try { 39 | var response = await searchMoviesShowsUseCase.searchMoviesShows( 40 | searchTerm: searchTerm); 41 | yield SuccessSuggestionsMoviesShowsState( 42 | MoviesShowsRecord.fromJson(response)); 43 | } catch (exception) { 44 | debugPrint('Error ${exception.toString()}'); 45 | yield ErrorMoviesShowsSearchState(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/bloc/search/movies_shows_search_event.dart: -------------------------------------------------------------------------------- 1 | class MoviesShowsSearchEvent { 2 | String event; 3 | String searchTerm; 4 | 5 | MoviesShowsSearchEvent({required this.event, required this.searchTerm}); 6 | } 7 | -------------------------------------------------------------------------------- /lib/bloc/search/movies_shows_search_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movies_shows_record.dart'; 2 | 3 | abstract class MoviesShowsSearchState {} 4 | 5 | class InitialMoviesShowsSearchState extends MoviesShowsSearchState {} 6 | 7 | class ProgressMoviesShowsSearchState extends MoviesShowsSearchState {} 8 | 9 | class SuccessSuggestionsMoviesShowsState extends MoviesShowsSearchState { 10 | final MoviesShowsRecord record; 11 | 12 | SuccessSuggestionsMoviesShowsState(this.record); 13 | } 14 | 15 | class ErrorMoviesShowsSearchState extends MoviesShowsSearchState {} 16 | -------------------------------------------------------------------------------- /lib/bloc/video/movie_show_trailer_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/trailer_record.dart'; 2 | import 'package:domain/usecase/video/movie_trailer_use_case.dart'; 3 | import 'package:domain/usecase/video/show_trailer_use_case.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:flutter_bloc/flutter_bloc.dart'; 6 | import 'package:fun_box/bloc/video/movie_show_trailer_event.dart'; 7 | import 'package:fun_box/bloc/video/movie_show_trailer_state.dart'; 8 | import 'package:fun_box/utils/app_constants.dart'; 9 | import 'package:injectable/injectable.dart'; 10 | 11 | @injectable 12 | class MovieShowTrailerBloc 13 | extends Bloc { 14 | final MovieTrailerUseCase movieTrailerUseCase; 15 | final ShowTrailerUseCase showTrailerUseCase; 16 | 17 | MovieShowTrailerBloc(this.movieTrailerUseCase, this.showTrailerUseCase) 18 | : super(InitialMovieShowTrailerState()); 19 | 20 | @override 21 | Stream mapEventToState( 22 | MovieShowTrailerEvent event) async* { 23 | switch (event.type) { 24 | case AppConstants.movie: 25 | yield* _fetchMovieTrailer(event.type, event.id); 26 | break; 27 | case AppConstants.tvShow: 28 | yield* _fetchTvShowTrailer(event.type, event.id); 29 | break; 30 | default: 31 | break; 32 | } 33 | } 34 | 35 | Stream _fetchMovieTrailer( 36 | String type, double id) async* { 37 | try { 38 | var response = 39 | await movieTrailerUseCase.getMovieTrailer(type: type, id: id); 40 | yield SuccessMovieShowTrailerState(TrailerRecord.fromJson(response)); 41 | } catch (exception) { 42 | debugPrint('Error ${exception.toString()}'); 43 | yield ErrorMovieShowTrailerState(); 44 | } 45 | } 46 | 47 | Stream _fetchTvShowTrailer( 48 | String type, double id) async* { 49 | try { 50 | var response = 51 | await showTrailerUseCase.getShowTrailer(type: type, id: id); 52 | yield SuccessMovieShowTrailerState(TrailerRecord.fromJson(response)); 53 | } catch (exception) { 54 | debugPrint('Error ${exception.toString()}'); 55 | yield ErrorMovieShowTrailerState(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/bloc/video/movie_show_trailer_event.dart: -------------------------------------------------------------------------------- 1 | class MovieShowTrailerEvent { 2 | final String type; 3 | final double id; 4 | 5 | MovieShowTrailerEvent({required this.type, required this.id}); 6 | } 7 | -------------------------------------------------------------------------------- /lib/bloc/video/movie_show_trailer_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/trailer_record.dart'; 2 | 3 | abstract class MovieShowTrailerState {} 4 | 5 | class InitialMovieShowTrailerState extends MovieShowTrailerState {} 6 | 7 | class SuccessMovieShowTrailerState extends MovieShowTrailerState { 8 | final TrailerRecord record; 9 | 10 | SuccessMovieShowTrailerState(this.record); 11 | } 12 | 13 | class ErrorMovieShowTrailerState extends MovieShowTrailerState {} 14 | -------------------------------------------------------------------------------- /lib/config/configurations.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:fun_box/config/default_config.dart'; 3 | import 'package:fun_box/utils/app_constants.dart'; 4 | import 'package:get_it/get_it.dart'; 5 | import 'package:domain/model/config_record.dart'; 6 | import 'package:domain/usecase/get_config_use_case.dart'; 7 | 8 | class Configurations { 9 | static String _configStatus = AppConstants.localConfig; 10 | static String _imageUrl = DefaultConfig.secureImageUrl; 11 | static String _imageSize = DefaultConfig.imageSize; 12 | 13 | final GetConfigUseCase _useCase = GetIt.instance.get(); 14 | 15 | Future getConfig() async { 16 | try { 17 | var response = await _useCase.getConfig(); 18 | var config = ConfigRecord.fromJson(response); 19 | var imageLength = 0; 20 | _configStatus = AppConstants.remoteConfig; 21 | _imageUrl = config.images?.secureBaseUrl ?? DefaultConfig.secureImageUrl; 22 | if (config.images?.logoSizes != null) { 23 | imageLength = config.images?.logoSizes!.length ?? 0; 24 | if (imageLength > 0) { 25 | _imageSize = config.images?.logoSizes![imageLength - 2] ?? 26 | DefaultConfig.imageSize; 27 | } 28 | } 29 | } catch (exception) { 30 | debugPrint('Error ${exception.toString()}'); 31 | } 32 | } 33 | 34 | static String get configStatus => _configStatus; 35 | 36 | static String get imageUrl => _imageUrl; 37 | 38 | static String get imageSize => _imageSize; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /lib/config/default_config.dart: -------------------------------------------------------------------------------- 1 | class DefaultConfig { 2 | static const baseUrl = 'https://api.themoviedb.org/3'; 3 | static const imageUrl = 'http://image.tmdb.org/t/p/'; 4 | static const secureImageUrl = 'https://image.tmdb.org/t/p/'; 5 | static const imageSize = 'w500'; 6 | } -------------------------------------------------------------------------------- /lib/di/di.config.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | // ************************************************************************** 4 | // InjectableConfigGenerator 5 | // ************************************************************************** 6 | 7 | import 'package:domain/usecase/cast/movie_cast_use_case.dart' as _i4; 8 | import 'package:domain/usecase/cast/show_cast_use_case.dart' as _i5; 9 | import 'package:domain/usecase/details/movie_details_use_case.dart' as _i7; 10 | import 'package:domain/usecase/details/show_details_use_case.dart' as _i8; 11 | import 'package:domain/usecase/filter/movie_filter_use_case.dart' as _i26; 12 | import 'package:domain/usecase/filter/show_filter_use_case.dart' as _i27; 13 | import 'package:domain/usecase/movies/current_playing_movies_use_case.dart' 14 | as _i13; 15 | import 'package:domain/usecase/movies/latest_movies_use_case.dart' as _i15; 16 | import 'package:domain/usecase/movies/movies_by_genres_use_case.dart' as _i18; 17 | import 'package:domain/usecase/movies/popular_movies_use_case.dart' as _i14; 18 | import 'package:domain/usecase/movies/top_rated_movies_use_case.dart' as _i16; 19 | import 'package:domain/usecase/movies/upcoming_movies_use_case.dart' as _i17; 20 | import 'package:domain/usecase/person/person_credits_use_case.dart' as _i32; 21 | import 'package:domain/usecase/person/person_info_use_case.dart' as _i31; 22 | import 'package:domain/usecase/search_movies_shows_use_case.dart' as _i29; 23 | import 'package:domain/usecase/shows/airing_today_shows_use_case.dart' as _i23; 24 | import 'package:domain/usecase/shows/current_playing_shows_use_case.dart' 25 | as _i19; 26 | import 'package:domain/usecase/shows/latest_shows_use_case.dart' as _i21; 27 | import 'package:domain/usecase/shows/popular_shows_use_case.dart' as _i20; 28 | import 'package:domain/usecase/shows/shows_by_genres_use_case.dart' as _i24; 29 | import 'package:domain/usecase/shows/top_rated_shows_use_case.dart' as _i22; 30 | import 'package:domain/usecase/trending/trending_movies_use_case.dart' as _i34; 31 | import 'package:domain/usecase/trending/trending_people_use_case.dart' as _i36; 32 | import 'package:domain/usecase/trending/trending_shows_use_case.dart' as _i35; 33 | import 'package:domain/usecase/video/movie_trailer_use_case.dart' as _i10; 34 | import 'package:domain/usecase/video/show_trailer_use_case.dart' as _i11; 35 | import 'package:get_it/get_it.dart' as _i1; 36 | import 'package:injectable/injectable.dart' as _i2; 37 | 38 | import '../bloc/all/trending_bloc.dart' as _i33; 39 | import '../bloc/cast/movie_show_cast_bloc.dart' as _i3; 40 | import '../bloc/details/movie_show_details_bloc.dart' as _i6; 41 | import '../bloc/filter/movies_shows_filter_bloc.dart' as _i25; 42 | import '../bloc/movieshow/movies_shows_bloc.dart' as _i12; 43 | import '../bloc/person/person_details_bloc.dart' as _i30; 44 | import '../bloc/search/movies_shows_search_bloc.dart' as _i28; 45 | import '../bloc/video/movie_show_trailer_bloc.dart' 46 | as _i9; // ignore_for_file: unnecessary_lambdas 47 | 48 | // ignore_for_file: lines_longer_than_80_chars 49 | /// initializes the registration of provided dependencies inside of [GetIt] 50 | _i1.GetIt $initGetIt(_i1.GetIt get, 51 | {String? environment, _i2.EnvironmentFilter? environmentFilter}) { 52 | final gh = _i2.GetItHelper(get, environment, environmentFilter); 53 | gh.factory<_i3.MovieShowCastBloc>(() => _i3.MovieShowCastBloc( 54 | get<_i4.MovieCastUseCase>(), get<_i5.ShowCastUseCase>())); 55 | gh.factory<_i6.MovieShowDetailsBloc>(() => _i6.MovieShowDetailsBloc( 56 | get<_i7.MovieDetailsUseCase>(), get<_i8.ShowDetailsUseCase>())); 57 | gh.factory<_i9.MovieShowTrailerBloc>(() => _i9.MovieShowTrailerBloc( 58 | get<_i10.MovieTrailerUseCase>(), get<_i11.ShowTrailerUseCase>())); 59 | gh.factory<_i12.MoviesShowsBloc>(() => _i12.MoviesShowsBloc( 60 | get<_i13.CurrentPlayingMoviesUseCase>(), 61 | get<_i14.PopularMoviesUseCase>(), 62 | get<_i15.LatestMoviesUseCase>(), 63 | get<_i16.TopRatedMoviesUseCase>(), 64 | get<_i17.UpcomingMoviesUseCase>(), 65 | get<_i18.MoviesByGenresUseCase>(), 66 | get<_i19.CurrentPlayingShowsUseCase>(), 67 | get<_i20.PopularShowsUseCase>(), 68 | get<_i21.LatestShowsUseCase>(), 69 | get<_i22.TopRatedShowsUseCase>(), 70 | get<_i23.AiringTodayShowsUseCase>(), 71 | get<_i24.ShowsByGenresUseCase>())); 72 | gh.factory<_i25.MoviesShowsFilterBloc>(() => _i25.MoviesShowsFilterBloc( 73 | get<_i26.MovieFilterUseCase>(), get<_i27.ShowFilterUseCase>())); 74 | gh.factory<_i28.MoviesShowsSearchBloc>( 75 | () => _i28.MoviesShowsSearchBloc(get<_i29.SearchMoviesShowsUseCase>())); 76 | gh.factory<_i30.PersonDetailsBloc>(() => _i30.PersonDetailsBloc( 77 | get<_i31.PersonInfoUseCase>(), get<_i32.PersonCreditsUseCase>())); 78 | gh.factory<_i33.TrendingBloc>(() => _i33.TrendingBloc( 79 | get<_i34.TrendingMoviesUseCase>(), 80 | get<_i35.TrendingShowsUseCase>(), 81 | get<_i36.TrendingPeopleUseCase>())); 82 | return get; 83 | } 84 | -------------------------------------------------------------------------------- /lib/di/di.dart: -------------------------------------------------------------------------------- 1 | import 'package:data/di/di.dart'; 2 | import 'package:domain/di/di.dart'; 3 | import 'package:fun_box/di/di.config.dart'; 4 | import 'package:get_it/get_it.dart'; 5 | import 'package:injectable/injectable.dart'; 6 | import 'package:remote/di/di.dart'; 7 | 8 | final GetIt _getIt = GetIt.instance; 9 | 10 | @InjectableInit( 11 | initializerName: r'$initGetIt' 12 | ) 13 | Future configureInjection() async { 14 | configureRemoteInjection(_getIt); 15 | configureDataInjection(_getIt); 16 | configureDomainInjection(_getIt); 17 | $initGetIt(_getIt); 18 | } -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:fun_box/config/configurations.dart'; 4 | import 'package:fun_box/di/di.dart'; 5 | import 'package:fun_box/presentation/home/home.dart'; 6 | import 'package:fun_box/utils/app_navigator_observer.dart'; 7 | import 'package:get_it/get_it.dart'; 8 | 9 | void main() async { 10 | WidgetsFlutterBinding.ensureInitialized(); 11 | GetIt.instance.allowReassignment = true; 12 | await configureInjection(); 13 | await Configurations().getConfig(); 14 | await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) 15 | .then((_) => runApp(MyApp())); 16 | } 17 | 18 | class MyApp extends StatelessWidget { 19 | // This widget is the root of your application. 20 | @override 21 | Widget build(BuildContext context) { 22 | final _observer = AppNavigatorObserver(); 23 | return MaterialApp( 24 | title: 'Fun Box', 25 | debugShowCheckedModeBanner: false, 26 | theme: ThemeData( 27 | primarySwatch: Colors.deepOrange, 28 | visualDensity: VisualDensity.adaptivePlatformDensity, 29 | ), 30 | navigatorObservers: [_observer], 31 | home: Home(), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/presentation/common/common_display_tiles.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movies_shows_record.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fun_box/config/configurations.dart'; 4 | import 'package:fun_box/presentation/details/movie_show_details.dart'; 5 | 6 | class CommonDisplayTiles extends StatelessWidget { 7 | final double width; 8 | final int itemCount; 9 | final List? results; 10 | final String type; 11 | 12 | CommonDisplayTiles( 13 | {required this.width, 14 | required this.itemCount, 15 | required this.results, 16 | required this.type}); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Container( 21 | height: width / 2, 22 | width: width, 23 | margin: EdgeInsets.only(bottom: 8.0), 24 | child: ListView.builder( 25 | scrollDirection: Axis.horizontal, 26 | itemCount: itemCount, 27 | itemBuilder: (context, index) { 28 | return _trendingMoviesShowsCell( 29 | context, 30 | results?[index].posterPath ?? '', 31 | type, 32 | results?[index].id?.toDouble() ?? 0); 33 | }), 34 | ); 35 | } 36 | 37 | Widget _trendingMoviesShowsCell( 38 | BuildContext context, String imagePath, String type, double id) { 39 | return GestureDetector( 40 | onTap: () => _navigateToDetails(context, type, id), 41 | child: Card( 42 | clipBehavior: Clip.antiAliasWithSaveLayer, 43 | elevation: 5.0, 44 | shape: RoundedRectangleBorder( 45 | borderRadius: BorderRadius.all(Radius.circular(10.0))), 46 | child: Image.network( 47 | '${Configurations.imageUrl}/${Configurations.imageSize}$imagePath', 48 | fit: BoxFit.cover, 49 | ), 50 | ), 51 | ); 52 | } 53 | 54 | void _navigateToDetails(BuildContext context, String type, double id) { 55 | Navigator.push(context, MaterialPageRoute(builder: (context) { 56 | return MovieShowDetails( 57 | type: type, 58 | id: id, 59 | ); 60 | })); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/presentation/common/common_error_ui.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fun_box/presentation/ui_constants.dart'; 3 | 4 | class ErrorUI extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Center( 8 | child: Column( 9 | children: [ 10 | Padding( 11 | padding: EdgeInsets.all(10.0), 12 | child: Image( 13 | image: AssetImage('images/error_image.png'), 14 | width: 125.0, 15 | height: 125.0, 16 | ), 17 | ), 18 | Text( 19 | UIConstants.errorMessage, 20 | style: TextStyle( 21 | fontSize: 14.0, 22 | fontFamily: UIConstants.fontFamilyIronclad, 23 | fontWeight: FontWeight.w400), 24 | ) 25 | ], 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/presentation/common/common_people_tiles.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/trending_people_record.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:fun_box/config/configurations.dart'; 4 | import 'package:fun_box/presentation/person/person_details.dart'; 5 | 6 | class CommonPeopleTiles extends StatelessWidget { 7 | final double radius; 8 | final double width; 9 | final int itemCount; 10 | final List? results; 11 | 12 | CommonPeopleTiles( 13 | {required this.radius, 14 | required this.width, 15 | required this.itemCount, 16 | required this.results}); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Container( 21 | height: width / 2, 22 | width: width, 23 | margin: EdgeInsets.only(top: 8.0, bottom: 8.0), 24 | child: ListView.builder( 25 | scrollDirection: Axis.horizontal, 26 | itemCount: itemCount, 27 | itemBuilder: (context, index) { 28 | return _trendingPeopleCell( 29 | context, 30 | results?[index].profilePath ?? '', 31 | results?[index].id?.toDouble() ?? 0); 32 | }), 33 | ); 34 | } 35 | 36 | Widget _trendingPeopleCell( 37 | BuildContext context, String imagePath, double id) { 38 | return GestureDetector( 39 | onTap: () => _navigateToPersonDetails(context, id), 40 | child: Card( 41 | clipBehavior: Clip.antiAliasWithSaveLayer, 42 | elevation: 5.0, 43 | shape: RoundedRectangleBorder( 44 | borderRadius: BorderRadius.all(Radius.circular(10.0))), 45 | child: Image.network( 46 | '${Configurations.imageUrl}/${Configurations.imageSize}$imagePath', 47 | fit: BoxFit.cover, 48 | ), 49 | ), 50 | ); 51 | } 52 | 53 | void _navigateToPersonDetails(BuildContext context, double id) { 54 | Navigator.push(context, MaterialPageRoute(builder: (context) { 55 | return PersonDetails(id: id); 56 | })); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/presentation/common/common_search_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fun_box/config/configurations.dart'; 3 | import 'package:fun_box/presentation/search/search.dart'; 4 | import 'package:fun_box/utils/app_constants.dart'; 5 | 6 | import '../ui_constants.dart'; 7 | 8 | class CommonSearchBar extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return Padding( 12 | padding: EdgeInsets.all(10.0), 13 | child: Theme( 14 | data: ThemeData(primaryColor: Colors.black), 15 | child: TextField( 16 | focusNode: SearchFocusNode(), 17 | style: TextStyle( 18 | fontFamily: UIConstants.fontFamilyIronclad, 19 | fontWeight: FontWeight.w400, 20 | fontSize: 16.0 21 | ), 22 | decoration: InputDecoration( 23 | prefixIcon: Icon(Icons.search), 24 | hintText: UIConstants.searchHint, 25 | border: OutlineInputBorder( 26 | borderRadius: BorderRadius.circular(30.0))), 27 | onTap: () { 28 | Navigator.push(context, MaterialPageRoute(builder: (context) { 29 | return Search(); 30 | })); 31 | }, 32 | ), 33 | ), 34 | ); 35 | } 36 | } 37 | 38 | class SearchFocusNode extends FocusNode { 39 | @override 40 | bool get hasFocus { 41 | return Configurations.configStatus == AppConstants.remoteConfig; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/presentation/common/common_widgets.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CommonProgressBar extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return Center( 7 | child: CircularProgressIndicator(), 8 | ); 9 | } 10 | } 11 | 12 | class CommonEmptyInit extends StatelessWidget { 13 | @override 14 | Widget build(BuildContext context) { 15 | return SizedBox(); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /lib/presentation/details/movie_show_details.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fun_box/presentation/details/widgets/movie_show_cast.dart'; 3 | import 'package:fun_box/presentation/details/widgets/movie_show_info.dart'; 4 | 5 | class MovieShowDetails extends StatefulWidget { 6 | final String type; 7 | final double id; 8 | 9 | MovieShowDetails({required this.type, required this.id}); 10 | 11 | @override 12 | State createState() => _MovieShowDetailsState(type, id); 13 | } 14 | 15 | class _MovieShowDetailsState extends State { 16 | final String type; 17 | final double id; 18 | 19 | _MovieShowDetailsState(this.type, this.id); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return Material( 24 | child: SafeArea( 25 | child: ListView( 26 | shrinkWrap: true, 27 | children: [ 28 | MovieShowInfo(type: type, id: id), 29 | Padding( 30 | padding: EdgeInsets.only(top: 24.0, left: 16.0, right: 16.0), 31 | child: MovieShowCast(type: type, id: id), 32 | ) 33 | ], 34 | ), 35 | ), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/presentation/filter/filters.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fun_box/presentation/filter/movies_shows_filters.dart'; 3 | 4 | import '../ui_constants.dart'; 5 | 6 | class Filters extends StatefulWidget { 7 | final String type; 8 | final String selectedValue; 9 | 10 | Filters({required this.type, required this.selectedValue}); 11 | 12 | @override 13 | State createState() => _FiltersState(type, selectedValue); 14 | } 15 | 16 | class _FiltersState extends State { 17 | final String type; 18 | final String selectedValue; 19 | 20 | _FiltersState(this.type, this.selectedValue); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Material( 25 | child: SafeArea( 26 | child: Column( 27 | children: [ 28 | Container( 29 | decoration: BoxDecoration( 30 | border: Border( 31 | bottom: BorderSide(color: Colors.grey, width: 0.5))), 32 | child: Row( 33 | children: [ 34 | GestureDetector( 35 | onTap: () => _navigateToMoviesShows(context), 36 | child: Padding( 37 | padding: 38 | EdgeInsets.only(top: 10.0, bottom: 10.0, left: 10.0), 39 | child: Align( 40 | alignment: Alignment.centerLeft, 41 | child: Icon( 42 | Icons.clear_rounded, 43 | size: 30.0, 44 | ), 45 | ), 46 | ), 47 | ), 48 | Expanded( 49 | child: Padding( 50 | padding: 51 | EdgeInsets.only(top: 10.0, bottom: 10.0, right: 10.0), 52 | child: Center( 53 | child: Text( 54 | UIConstants.filters, 55 | style: TextStyle( 56 | color: Colors.black, 57 | fontSize: 20.0, 58 | fontFamily: UIConstants.fontFamilyIronclad, 59 | fontWeight: FontWeight.w700), 60 | ), 61 | ), 62 | )) 63 | ], 64 | ), 65 | ), 66 | MoviesShowsFilters(type: type, selectedValue: selectedValue) 67 | ], 68 | ), 69 | ), 70 | ); 71 | } 72 | 73 | void _navigateToMoviesShows(BuildContext context) { 74 | Navigator.pop(context, ''); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/presentation/home/home.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fun_box/presentation/common/common_search_bar.dart'; 3 | import 'package:fun_box/presentation/home/widgets/trending_movies.dart'; 4 | import 'package:fun_box/presentation/home/widgets/trending_people.dart'; 5 | import 'package:fun_box/presentation/home/widgets/trending_shows.dart'; 6 | 7 | class Home extends StatefulWidget { 8 | @override 9 | State createState() => _HomeState(); 10 | } 11 | 12 | class _HomeState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Material( 16 | child: SafeArea( 17 | child: ListView( 18 | children: [ 19 | CommonSearchBar(), 20 | Padding( 21 | padding: EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0), 22 | child: TrendingMovies(), 23 | ), 24 | Padding( 25 | padding: EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0), 26 | child: TrendingShows(), 27 | ), 28 | Padding( 29 | padding: EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0), 30 | child: TrendingPeople(), 31 | ) 32 | ], 33 | ))); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/presentation/home/widgets/trending_movies.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movies_shows_record.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:fun_box/bloc/all/trending_bloc.dart'; 5 | import 'package:fun_box/bloc/all/trending_event.dart'; 6 | import 'package:fun_box/bloc/all/trending_state.dart'; 7 | import 'package:fun_box/presentation/common/common_display_tiles.dart'; 8 | import 'package:fun_box/presentation/common/common_error_ui.dart'; 9 | import 'package:fun_box/presentation/common/common_widgets.dart'; 10 | import 'package:fun_box/presentation/movieshow/movies_shows.dart'; 11 | import 'package:fun_box/presentation/ui_constants.dart'; 12 | import 'package:fun_box/utils/app_constants.dart'; 13 | import 'package:get_it/get_it.dart'; 14 | 15 | class TrendingMovies extends StatefulWidget { 16 | @override 17 | State createState() => _TrendingMoviesState(); 18 | } 19 | 20 | class _TrendingMoviesState extends State { 21 | final TrendingBloc _trendingBloc = GetIt.instance.get(); 22 | 23 | @override 24 | void dispose() { 25 | _trendingBloc.close(); 26 | super.dispose(); 27 | } 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | BlocProvider(create: (BuildContext context) => _trendingBloc); 32 | _trendingBloc.add(TrendingEvent.movie); 33 | return BlocBuilder( 34 | bloc: _trendingBloc, 35 | builder: (context, state) { 36 | if (state is InitialTrendingMoviesShowsState) { 37 | return _initState(); 38 | } else if (state is SuccessTrendingMoviesState) { 39 | return _trendingMovies(context, state.record); 40 | } else if (state is ErrorMoviesShowsState) { 41 | return _error(); 42 | } else { 43 | return _error(); 44 | } 45 | }, 46 | ); 47 | } 48 | 49 | Widget _trendingMovies(BuildContext context, MoviesShowsRecord trendingMovies) { 50 | final width = MediaQuery.of(context).size.width; 51 | return Column( 52 | children: [ 53 | Padding( 54 | padding: EdgeInsets.only(left: 8.0), 55 | child: Row( 56 | children: [ 57 | Text( 58 | UIConstants.trendingMovies, 59 | style: TextStyle( 60 | color: Colors.black, 61 | fontSize: 20.0, 62 | fontFamily: UIConstants.fontFamilyIronclad, 63 | fontWeight: FontWeight.w700), 64 | ), 65 | Expanded(child: SizedBox()), 66 | GestureDetector( 67 | onTap: () => _navigateToMovies(context), 68 | child: Icon( 69 | Icons.arrow_right_alt_rounded, 70 | size: 40.0, 71 | ), 72 | ) 73 | ], 74 | ), 75 | ), 76 | CommonDisplayTiles( 77 | width: width, 78 | itemCount: trendingMovies.results?.length ?? 0, 79 | results: trendingMovies.results, 80 | type: AppConstants.movie, 81 | ) 82 | ], 83 | ); 84 | } 85 | 86 | Widget _initState() { 87 | return CommonProgressBar(); 88 | } 89 | 90 | Widget _error() { 91 | return ErrorUI(); 92 | } 93 | 94 | void _navigateToMovies(BuildContext context) { 95 | Navigator.push(context, MaterialPageRoute(builder: (context) { 96 | return MoviesShows(type: AppConstants.movie); 97 | })); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lib/presentation/home/widgets/trending_people.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/trending_people_record.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:fun_box/bloc/all/trending_bloc.dart'; 5 | import 'package:fun_box/bloc/all/trending_event.dart'; 6 | import 'package:fun_box/bloc/all/trending_state.dart'; 7 | import 'package:fun_box/presentation/common/common_error_ui.dart'; 8 | import 'package:fun_box/presentation/common/common_people_tiles.dart'; 9 | import 'package:fun_box/presentation/common/common_widgets.dart'; 10 | import 'package:get_it/get_it.dart'; 11 | 12 | import '../../ui_constants.dart'; 13 | 14 | class TrendingPeople extends StatefulWidget { 15 | @override 16 | State createState() => _TrendingPeopleState(); 17 | } 18 | 19 | class _TrendingPeopleState extends State { 20 | final TrendingBloc _trendingBloc = GetIt.instance.get(); 21 | 22 | @override 23 | void dispose() { 24 | _trendingBloc.close(); 25 | super.dispose(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | BlocProvider(create: (BuildContext context) => _trendingBloc); 31 | _trendingBloc.add(TrendingEvent.person); 32 | return BlocBuilder( 33 | bloc: _trendingBloc, 34 | builder: (context, state) { 35 | if (state is InitialTrendingMoviesShowsState) { 36 | return _initState(); 37 | } else if (state is SuccessTrendingPersonState) { 38 | return _trendingPeople(context, state.record); 39 | } else { 40 | return _error(); 41 | } 42 | }, 43 | ); 44 | } 45 | 46 | Widget _trendingPeople( 47 | BuildContext context, TrendingPeopleRecord trendingPeople) { 48 | final width = MediaQuery.of(context).size.width; 49 | return Column( 50 | children: [ 51 | Padding( 52 | padding: EdgeInsets.only(left: 8.0), 53 | child: Align( 54 | alignment: Alignment.centerLeft, 55 | child: Text( 56 | UIConstants.trendingPeople, 57 | style: TextStyle( 58 | color: Colors.black, 59 | fontSize: 20.0, 60 | fontFamily: UIConstants.fontFamilyIronclad, 61 | fontWeight: FontWeight.w700), 62 | ), 63 | ), 64 | ), 65 | CommonPeopleTiles( 66 | radius: 20.0, 67 | width: width, 68 | itemCount: trendingPeople.results?.length ?? 0, 69 | results: trendingPeople.results) 70 | ], 71 | ); 72 | } 73 | 74 | Widget _initState() { 75 | return CommonEmptyInit(); 76 | } 77 | 78 | Widget _error() { 79 | return ErrorUI(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/presentation/home/widgets/trending_shows.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movies_shows_record.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:fun_box/bloc/all/trending_bloc.dart'; 5 | import 'package:fun_box/bloc/all/trending_event.dart'; 6 | import 'package:fun_box/bloc/all/trending_state.dart'; 7 | import 'package:fun_box/presentation/common/common_display_tiles.dart'; 8 | import 'package:fun_box/presentation/common/common_error_ui.dart'; 9 | import 'package:fun_box/presentation/common/common_widgets.dart'; 10 | import 'package:fun_box/presentation/movieshow/movies_shows.dart'; 11 | import 'package:fun_box/utils/app_constants.dart'; 12 | import 'package:get_it/get_it.dart'; 13 | 14 | import '../../ui_constants.dart'; 15 | 16 | class TrendingShows extends StatefulWidget { 17 | @override 18 | State createState() => _TrendingShowsState(); 19 | } 20 | 21 | class _TrendingShowsState extends State { 22 | final TrendingBloc _trendingBloc = GetIt.instance.get(); 23 | 24 | @override 25 | void dispose() { 26 | _trendingBloc.close(); 27 | super.dispose(); 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | BlocProvider(create: (BuildContext context) => _trendingBloc); 33 | _trendingBloc.add(TrendingEvent.tv); 34 | return BlocBuilder( 35 | bloc: _trendingBloc, 36 | builder: (context, state) { 37 | if (state is InitialTrendingMoviesShowsState) { 38 | return _initState(); 39 | } else if (state is SuccessTrendingShowsState) { 40 | return _trendingShows(context, state.record); 41 | } else if (state is ErrorMoviesShowsState) { 42 | return _error(); 43 | } else { 44 | return _error(); 45 | } 46 | }, 47 | ); 48 | } 49 | 50 | Widget _trendingShows(BuildContext context, MoviesShowsRecord trendingShows) { 51 | final width = MediaQuery.of(context).size.width; 52 | return Column( 53 | children: [ 54 | Padding( 55 | padding: EdgeInsets.only(left: 8.0), 56 | child: Row( 57 | children: [ 58 | Text( 59 | UIConstants.trendingShows, 60 | style: TextStyle( 61 | color: Colors.black, 62 | fontSize: 20.0, 63 | fontFamily: UIConstants.fontFamilyIronclad, 64 | fontWeight: FontWeight.w700), 65 | ), 66 | Expanded(child: SizedBox()), 67 | GestureDetector( 68 | onTap: () => _navigateToShows(context), 69 | child: Icon( 70 | Icons.arrow_right_alt_rounded, 71 | size: 40.0, 72 | ), 73 | ) 74 | ], 75 | ), 76 | ), 77 | CommonDisplayTiles( 78 | width: width, 79 | itemCount: trendingShows.results?.length ?? 0, 80 | results: trendingShows.results, 81 | type: AppConstants.tvShow, 82 | ) 83 | ], 84 | ); 85 | } 86 | 87 | Widget _initState() { 88 | return CommonEmptyInit(); 89 | } 90 | 91 | Widget _error() { 92 | return ErrorUI(); 93 | } 94 | 95 | void _navigateToShows(BuildContext context) { 96 | Navigator.push(context, MaterialPageRoute(builder: (context) { 97 | return MoviesShows(type: AppConstants.tvShow); 98 | })); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /lib/presentation/movieshow/movies_shows.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fun_box/presentation/common/common_search_bar.dart'; 3 | import 'package:fun_box/presentation/filter/filters.dart'; 4 | import 'package:fun_box/presentation/movieshow/widgets/most_popular.dart'; 5 | import 'package:fun_box/utils/app_constants.dart'; 6 | 7 | class MoviesShows extends StatefulWidget { 8 | final String type; 9 | 10 | MoviesShows({required this.type}); 11 | 12 | @override 13 | State createState() => _MoviesShowsState(type); 14 | } 15 | 16 | class _MoviesShowsState extends State { 17 | final String type; 18 | var filter = '${AppConstants.sortBy},${AppConstants.popular}'; 19 | 20 | _MoviesShowsState(this.type); 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return Material( 25 | child: SafeArea( 26 | child: Column( 27 | children: [ 28 | Row( 29 | children: [ 30 | GestureDetector( 31 | onTap: () => _navigateToHome(context), 32 | child: Padding( 33 | padding: 34 | EdgeInsets.only(top: 10.0, bottom: 10.0, left: 10.0), 35 | child: Align( 36 | alignment: Alignment.centerLeft, 37 | child: Icon( 38 | Icons.arrow_back_rounded, 39 | size: 30.0, 40 | ), 41 | ), 42 | ), 43 | ), 44 | Expanded(child: CommonSearchBar()), 45 | GestureDetector( 46 | onTap: () => _navigateToFilters(context), 47 | child: Padding( 48 | padding: 49 | EdgeInsets.only(top: 10.0, bottom: 10.0, right: 10.0), 50 | child: Align( 51 | alignment: Alignment.centerLeft, 52 | child: Icon( 53 | Icons.filter_list_rounded, 54 | size: 30.0, 55 | ), 56 | ), 57 | ), 58 | ) 59 | ], 60 | ), 61 | MostPopular(type: type, filter: filter) 62 | ], 63 | ), 64 | ), 65 | ); 66 | } 67 | 68 | void _navigateToHome(BuildContext context) { 69 | Navigator.pop(context); 70 | } 71 | 72 | void _navigateToFilters(BuildContext context) async { 73 | var result = 74 | await Navigator.push(context, MaterialPageRoute(builder: (context) { 75 | return Filters(type: type, selectedValue: filter); 76 | })); 77 | 78 | if(result != '') { 79 | setState(() { 80 | filter = result; 81 | }); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/presentation/movieshow/widgets/currently_playing.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movies_shows_record.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:fun_box/bloc/movieshow/movies_shows_bloc.dart'; 5 | import 'package:fun_box/bloc/movieshow/movies_shows_event.dart'; 6 | import 'package:fun_box/bloc/movieshow/movies_shows_state.dart'; 7 | import 'package:fun_box/presentation/common/common_display_tiles.dart'; 8 | import 'package:fun_box/presentation/common/common_error_ui.dart'; 9 | import 'package:fun_box/presentation/common/common_widgets.dart'; 10 | import 'package:fun_box/utils/app_constants.dart'; 11 | import 'package:get_it/get_it.dart'; 12 | 13 | import '../../ui_constants.dart'; 14 | 15 | class CurrentlyPlaying extends StatefulWidget { 16 | final String type; 17 | 18 | CurrentlyPlaying({required this.type}); 19 | 20 | @override 21 | State createState() => _CurrentlyPlayingState(type); 22 | } 23 | 24 | class _CurrentlyPlayingState extends State { 25 | final String type; 26 | final MoviesShowsBloc _moviesShowsBloc = 27 | GetIt.instance.get(); 28 | 29 | _CurrentlyPlayingState(this.type); 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | BlocProvider(create: (BuildContext context) => _moviesShowsBloc); 34 | _moviesShowsBloc.add( 35 | MoviesShowsEvent(type: type, event: AppConstants.currentlyPlaying, page: 1)); 36 | return BlocBuilder( 37 | bloc: _moviesShowsBloc, 38 | builder: (context, state) { 39 | if (state is InitialMoviesShowsState) { 40 | return _initState(); 41 | } else if (state is SuccessMoviesShowsState) { 42 | return _showCurrentPlaying(context, state.record); 43 | } else if (state is ErrorMoviesShowsState) { 44 | return _errorState(); 45 | } else { 46 | return _errorState(); 47 | } 48 | }); 49 | } 50 | 51 | Widget _showCurrentPlaying( 52 | BuildContext context, MoviesShowsRecord currentPlaying) { 53 | final width = MediaQuery.of(context).size.width; 54 | return Column( 55 | children: [ 56 | Padding( 57 | padding: EdgeInsets.only(left: 8.0, top: 8.0, bottom: 8.0), 58 | child: Align( 59 | alignment: Alignment.centerLeft, 60 | child: Text( 61 | UIConstants.currentlyPlaying, 62 | style: TextStyle( 63 | color: Colors.black, 64 | fontSize: 20.0, 65 | fontFamily: UIConstants.fontFamilyIronclad, 66 | fontWeight: FontWeight.w700), 67 | ), 68 | ), 69 | ), 70 | Padding( 71 | padding: EdgeInsets.only(left: 8.0, right: 8.0), 72 | child: CommonDisplayTiles( 73 | width: width, 74 | itemCount: currentPlaying.results?.length ?? 0, 75 | results: currentPlaying.results, 76 | type: type), 77 | ) 78 | ], 79 | ); 80 | } 81 | 82 | Widget _initState() { 83 | return CommonProgressBar(); 84 | } 85 | 86 | Widget _errorState() { 87 | return ErrorUI(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /lib/presentation/movieshow/widgets/most_popular.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/movies_shows_record.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:fun_box/bloc/movieshow/movies_shows_bloc.dart'; 5 | import 'package:fun_box/bloc/movieshow/movies_shows_event.dart'; 6 | import 'package:fun_box/bloc/movieshow/movies_shows_state.dart'; 7 | import 'package:fun_box/config/configurations.dart'; 8 | import 'package:fun_box/presentation/common/common_error_ui.dart'; 9 | import 'package:fun_box/presentation/common/common_widgets.dart'; 10 | import 'package:fun_box/presentation/details/movie_show_details.dart'; 11 | import 'package:fun_box/utils/app_constants.dart'; 12 | import 'package:get_it/get_it.dart'; 13 | 14 | class MostPopular extends StatefulWidget { 15 | final String type; 16 | final String filter; 17 | 18 | MostPopular({required this.type, required this.filter}); 19 | 20 | @override 21 | State createState() => _MostPopularState(type, filter); 22 | } 23 | 24 | class _MostPopularState extends State { 25 | final String type; 26 | final String filter; 27 | final MoviesShowsBloc _moviesShowsBloc = 28 | GetIt.instance.get(); 29 | var _page = 1; 30 | 31 | _MostPopularState(this.type, this.filter); 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | final List _popularList = []; 36 | BlocProvider(create: (BuildContext context) => _moviesShowsBloc); 37 | _moviesShowsBloc.add(MoviesShowsEvent( 38 | type: type, event: filter, page: _page)); 39 | return BlocBuilder( 40 | bloc: _moviesShowsBloc, 41 | builder: (context, state) { 42 | if (state is InitialMoviesShowsState) { 43 | return _initState(); 44 | } else if (state is SuccessMoviesShowsState) { 45 | _page = _page + 1; 46 | _popularList.addAll(state.record.results!); 47 | return _showPopular(context, type, _popularList); 48 | } else if (state is ErrorMoviesShowsState) { 49 | return _errorState(); 50 | } else { 51 | return _errorState(); 52 | } 53 | }); 54 | } 55 | 56 | Widget _showPopular( 57 | BuildContext context, String type, List popularList) { 58 | final width = MediaQuery.of(context).size.width; 59 | final height = MediaQuery.of(context).size.height; 60 | final itemWidth = width / 2; 61 | final ScrollController _scrollController = ScrollController(); 62 | return Container( 63 | width: width, 64 | height: height - 120.0, 65 | child: Padding( 66 | padding: EdgeInsets.only(left: 8.0, right: 8.0), 67 | child: GridView.builder( 68 | controller: _scrollController 69 | ..addListener(() { 70 | if (_scrollController.offset == 71 | _scrollController.position.maxScrollExtent && 72 | _page < AppConstants.maxPages) { 73 | _moviesShowsBloc.add(MoviesShowsEvent( 74 | type: type, event: filter, page: _page)); 75 | } 76 | }), 77 | itemCount: popularList.length, 78 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 79 | childAspectRatio: itemWidth / (itemWidth + 100), 80 | crossAxisCount: 2, 81 | crossAxisSpacing: 5.0, 82 | mainAxisSpacing: 5.0), 83 | itemBuilder: (context, index) { 84 | return _popularCell( 85 | context, 86 | type, 87 | popularList[index].id?.toDouble() ?? 0, 88 | popularList[index].posterPath ?? ''); 89 | }), 90 | ), 91 | ); 92 | } 93 | 94 | Widget _popularCell( 95 | BuildContext context, String type, double id, String imagePath) { 96 | return GestureDetector( 97 | onTap: () => _navigateToDetails(context, type, id), 98 | child: Card( 99 | clipBehavior: Clip.antiAliasWithSaveLayer, 100 | elevation: 5.0, 101 | shape: RoundedRectangleBorder( 102 | borderRadius: BorderRadius.all(Radius.circular(10.0))), 103 | child: Image.network( 104 | '${Configurations.imageUrl}/${Configurations.imageSize}$imagePath', 105 | fit: BoxFit.cover, 106 | ), 107 | ), 108 | ); 109 | } 110 | 111 | Widget _initState() { 112 | return CommonProgressBar(); 113 | } 114 | 115 | Widget _errorState() { 116 | return ErrorUI(); 117 | } 118 | 119 | void _navigateToDetails(BuildContext context, String type, double id) { 120 | Navigator.push(context, MaterialPageRoute(builder: (context) { 121 | return MovieShowDetails( 122 | type: type, 123 | id: id, 124 | ); 125 | })); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /lib/presentation/person/person_details.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fun_box/presentation/person/widgets/person_credits.dart'; 3 | import 'package:fun_box/presentation/person/widgets/person_info.dart'; 4 | 5 | class PersonDetails extends StatefulWidget { 6 | final double id; 7 | 8 | PersonDetails({required this.id}); 9 | 10 | @override 11 | State createState() => _PersonDetailsState(id); 12 | } 13 | 14 | class _PersonDetailsState extends State { 15 | final double id; 16 | 17 | _PersonDetailsState(this.id); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return Material( 22 | child: SafeArea( 23 | child: ListView( 24 | shrinkWrap: true, 25 | children: [ 26 | PersonInfo(id: id), 27 | PersonCredits(id: id) 28 | ], 29 | ), 30 | ), 31 | ); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /lib/presentation/person/widgets/person_credits.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/person_credits_record.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | import 'package:fun_box/bloc/person/person_details_bloc.dart'; 6 | import 'package:fun_box/bloc/person/person_details_event.dart'; 7 | import 'package:fun_box/bloc/person/person_details_state.dart'; 8 | import 'package:fun_box/config/configurations.dart'; 9 | import 'package:fun_box/presentation/common/common_error_ui.dart'; 10 | import 'package:fun_box/presentation/common/common_widgets.dart'; 11 | import 'package:fun_box/presentation/details/movie_show_details.dart'; 12 | import 'package:fun_box/presentation/ui_constants.dart'; 13 | import 'package:fun_box/utils/app_constants.dart'; 14 | import 'package:get_it/get_it.dart'; 15 | 16 | class PersonCredits extends StatefulWidget { 17 | final double id; 18 | 19 | PersonCredits({required this.id}); 20 | 21 | @override 22 | State createState() => _PersonCreditsState(id); 23 | } 24 | 25 | class _PersonCreditsState extends State { 26 | final double id; 27 | final PersonDetailsBloc _personDetailsBloc = 28 | GetIt.instance.get(); 29 | 30 | _PersonCreditsState(this.id); 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | BlocProvider(create: (BuildContext context) => _personDetailsBloc); 35 | _personDetailsBloc 36 | .add(PersonDetailsEvent(type: AppConstants.credits, id: id)); 37 | return BlocBuilder( 38 | bloc: _personDetailsBloc, 39 | builder: (context, state) { 40 | if (state is InitialPersonDetailsState) { 41 | return _initState(); 42 | } else if (state is SuccessPersonCreditsState) { 43 | return _showCredits(context, state.record); 44 | } else if (state is ErrorPersonDetailsState) { 45 | return _errorState(); 46 | } else { 47 | return _errorState(); 48 | } 49 | }); 50 | } 51 | 52 | Widget _showCredits(BuildContext context, PersonCreditsRecord credits) { 53 | return Column( 54 | children: [ 55 | Padding( 56 | padding: EdgeInsets.all(10.0), 57 | child: Align( 58 | alignment: Alignment.centerLeft, 59 | child: Text( 60 | UIConstants.popular, 61 | style: TextStyle( 62 | color: Colors.black, 63 | fontFamily: UIConstants.fontFamilyMetropolis, 64 | fontSize: 20.0, 65 | fontWeight: FontWeight.w700), 66 | ), 67 | ), 68 | ), 69 | _showPopular(context, credits) 70 | ], 71 | ); 72 | } 73 | 74 | Widget _showPopular(BuildContext context, PersonCreditsRecord credits) { 75 | final width = MediaQuery.of(context).size.width; 76 | var _itemCount = 0; 77 | if (credits.cast != null && credits.cast!.length < 10) { 78 | _itemCount = credits.cast!.length; 79 | } else { 80 | _itemCount = 10; 81 | } 82 | return Container( 83 | height: width / 2, 84 | width: width, 85 | margin: EdgeInsets.only(bottom: 8.0), 86 | child: ListView.builder( 87 | scrollDirection: Axis.horizontal, 88 | itemCount: _itemCount, 89 | itemBuilder: (context, index) { 90 | var type = ''; 91 | if (credits.cast?[index].mediaType == AppConstants.movie) { 92 | type = AppConstants.movie; 93 | } else { 94 | type = AppConstants.tvShow; 95 | } 96 | return _popularCell(context, credits.cast?[index].posterPath ?? '', 97 | type, credits.cast?[index].id?.toDouble() ?? 0); 98 | }), 99 | ); 100 | } 101 | 102 | Widget _popularCell( 103 | BuildContext context, String imagePath, String type, double id) { 104 | return GestureDetector( 105 | onTap: () => _navigateToDetails(context, type, id), 106 | child: Card( 107 | clipBehavior: Clip.antiAliasWithSaveLayer, 108 | elevation: 5.0, 109 | shape: RoundedRectangleBorder( 110 | borderRadius: BorderRadius.all(Radius.circular(10.0))), 111 | child: Image.network( 112 | '${Configurations.imageUrl}/${Configurations.imageSize}$imagePath', 113 | fit: BoxFit.cover, 114 | ), 115 | ), 116 | ); 117 | } 118 | 119 | Widget _initState() { 120 | return CommonEmptyInit(); 121 | } 122 | 123 | Widget _errorState() { 124 | return ErrorUI(); 125 | } 126 | 127 | void _navigateToDetails(BuildContext context, String type, double id) { 128 | Navigator.push(context, MaterialPageRoute(builder: (context) { 129 | return MovieShowDetails( 130 | type: type, 131 | id: id, 132 | ); 133 | })); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /lib/presentation/ui_constants.dart: -------------------------------------------------------------------------------- 1 | class UIConstants { 2 | static const searchHint = 'Search...'; 3 | static const trendingToday = 'Trending Today'; 4 | static const trendingMovies = 'Movies'; 5 | static const trendingShows = 'TV Shows'; 6 | static const trendingPeople = 'People'; 7 | static const rating = 'Rating'; 8 | static const release = 'Release'; 9 | static const seasons = 'Seasons'; 10 | static const episodes = 'Episodes'; 11 | static const cast = 'Cast'; 12 | static const popular = 'Popular'; 13 | static const filters = 'Filters'; 14 | static const sortBy = 'Sort By'; 15 | static const genres = 'Genres'; 16 | static const currentlyPlaying = 'Currently Playing'; 17 | static const errorMessage = 'Oops! There was an error'; 18 | static const fontFamilyIronclad = 'iron'; 19 | static const fontFamilyMetropolis = 'metropolis'; 20 | } -------------------------------------------------------------------------------- /lib/presentation/video/movie_show_trailer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:fun_box/presentation/video/video_player.dart'; 3 | 4 | class MovieShowTrailer extends StatefulWidget { 5 | final String type; 6 | final double id; 7 | 8 | MovieShowTrailer({required this.type, required this.id}); 9 | 10 | @override 11 | State createState() => _MovieShowTrailerState(type, id); 12 | } 13 | 14 | class _MovieShowTrailerState extends State { 15 | final String type; 16 | final double id; 17 | 18 | _MovieShowTrailerState(this.type, this.id); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Material( 23 | child: SafeArea( 24 | child: VideoPlayer(type: type, id: id), 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/presentation/video/video_player.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/model/trailer_record.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:fun_box/bloc/video/movie_show_trailer_bloc.dart'; 5 | import 'package:fun_box/bloc/video/movie_show_trailer_event.dart'; 6 | import 'package:fun_box/bloc/video/movie_show_trailer_state.dart'; 7 | import 'package:fun_box/presentation/common/common_error_ui.dart'; 8 | import 'package:fun_box/presentation/common/common_widgets.dart'; 9 | import 'package:fun_box/utils/app_constants.dart'; 10 | import 'package:get_it/get_it.dart'; 11 | import 'package:youtube_player_flutter/youtube_player_flutter.dart'; 12 | 13 | class VideoPlayer extends StatefulWidget { 14 | final String type; 15 | final double id; 16 | 17 | VideoPlayer({required this.type, required this.id}); 18 | 19 | @override 20 | State createState() => _VideoPlayerState(type, id); 21 | } 22 | 23 | class _VideoPlayerState extends State { 24 | final String type; 25 | final double id; 26 | final MovieShowTrailerBloc _movieShowTrailerBloc = 27 | GetIt.instance.get(); 28 | 29 | _VideoPlayerState(this.type, this.id); 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | BlocProvider(create: (BuildContext context) => _movieShowTrailerBloc); 34 | _movieShowTrailerBloc.add(MovieShowTrailerEvent(type: type, id: id)); 35 | return BlocBuilder( 36 | bloc: _movieShowTrailerBloc, 37 | builder: (context, state) { 38 | if (state is InitialMovieShowTrailerState) { 39 | return _initState(); 40 | } else if (state is SuccessMovieShowTrailerState) { 41 | return _playTrailer(state.record); 42 | } else if (state is ErrorMovieShowTrailerState) { 43 | return _errorState(); 44 | } else { 45 | return _errorState(); 46 | } 47 | }); 48 | } 49 | 50 | Widget _playTrailer(TrailerRecord trailers) { 51 | var trailer = ''; 52 | if (trailers.results != null && trailers.results!.length > 0) { 53 | for (var i = 0; i < trailers.results!.length; i++) { 54 | if (trailers.results![i].name == AppConstants.trailer) { 55 | trailer = trailers.results![i].key ?? ''; 56 | } 57 | } 58 | if (trailer.isEmpty) { 59 | trailer = trailers.results![0].key ?? ''; 60 | } 61 | } 62 | 63 | YoutubePlayerController _controller = YoutubePlayerController( 64 | initialVideoId: trailer, 65 | flags: YoutubePlayerFlags(autoPlay: true, loop: true)); 66 | return Container( 67 | child: YoutubePlayer( 68 | controller: _controller, 69 | ), 70 | ); 71 | } 72 | 73 | Widget _initState() { 74 | return CommonProgressBar(); 75 | } 76 | 77 | Widget _errorState() { 78 | return ErrorUI(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/utils/app_constants.dart: -------------------------------------------------------------------------------- 1 | class AppConstants { 2 | static const String localConfig = 'local_config'; 3 | static const String remoteConfig = 'remote_config'; 4 | static const String movie = 'movie'; 5 | static const String tvShow = 'tv'; 6 | static const String person = 'person'; 7 | static const String personalInfo = 'personal_info'; 8 | static const String credits = 'credits'; 9 | static const String sortBy = 'sort_by'; 10 | static const String genres = 'genres'; 11 | static const String popular = 'popular'; 12 | static const String currentlyPlaying = 'currently_playing'; 13 | static const String topRated = 'Top Rated'; 14 | static const String latest = 'Latest'; 15 | static const String upcoming = 'Upcoming'; 16 | static const String nowPlaying = 'Now Playing'; 17 | static const String airingToday = 'Airing Today'; 18 | static const String onTheAir = 'On The Air'; 19 | static const String suggestions = 'suggestions'; 20 | static const String search = 'search'; 21 | static const String progress = 'progress'; 22 | static const String yearFormat = 'yyyy'; 23 | static const String dateFormat = 'dd-MM-yyyy'; 24 | static const String NA = 'NA'; 25 | static const String trailer = 'Trailer'; 26 | static const List movieSortByList = ['Upcoming', 'Now Playing', 'Latest', 'Top Rated']; 27 | static const List showSortByList = ['Airing Today', 'On The Air', 'Latest', 'Top Rated']; 28 | static const int maxPages = 500; 29 | } -------------------------------------------------------------------------------- /lib/utils/app_navigator_observer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class AppNavigatorObserver extends NavigatorObserver { 5 | 6 | @override 7 | void didPush(Route route, Route? previousRoute) { 8 | _setOrientation(); 9 | } 10 | 11 | @override 12 | void didPop(Route route, Route? previousRoute) { 13 | _setOrientation(); 14 | } 15 | 16 | void _setOrientation() { 17 | SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); 18 | } 19 | } -------------------------------------------------------------------------------- /lib/utils/app_utility.dart: -------------------------------------------------------------------------------- 1 | import 'package:fun_box/utils/app_constants.dart'; 2 | import 'package:intl/intl.dart'; 3 | 4 | class AppUtility { 5 | static String getYearFromDate(String date) { 6 | if (date.isNotEmpty) { 7 | var parseDate = DateTime.parse(date); 8 | var formatter = DateFormat(AppConstants.yearFormat); 9 | return formatter.format(parseDate); 10 | } else { 11 | return AppConstants.NA; 12 | } 13 | } 14 | 15 | static String getCorrectDate(String date) { 16 | if (date.isNotEmpty) { 17 | var parseDate = DateTime.parse(date); 18 | var formatter = DateFormat(AppConstants.dateFormat); 19 | return formatter.format(parseDate); 20 | } else { 21 | return ''; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: fun_box 2 | description: Movies and Tv shows finder. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | 27 | 28 | # The following adds the Cupertino Icons font to your application. 29 | # Use with the CupertinoIcons class for iOS style icons. 30 | cupertino_icons: ^1.0.0 31 | intl: ^0.17.0 32 | flutter_bloc: ^7.0.0 33 | injectable: ^1.2.2 34 | get_it: ^6.0.0 35 | youtube_player_flutter: ^8.0.0 36 | 37 | data: 38 | path: ./data 39 | 40 | domain: 41 | path: ./domain 42 | 43 | remote: 44 | path: ./remote 45 | 46 | dev_dependencies: 47 | flutter_test: 48 | sdk: flutter 49 | injectable_generator: 1.2.2 50 | build_runner: 1.12.2 51 | 52 | # For information on the generic Dart part of this file, see the 53 | # following page: https://dart.dev/tools/pub/pubspec 54 | 55 | # The following section is specific to Flutter. 56 | flutter: 57 | 58 | # The following line ensures that the Material Icons font is 59 | # included with your application, so that you can use the icons in 60 | # the material Icons class. 61 | uses-material-design: true 62 | 63 | # To add assets to your application, add an assets section, like this: 64 | assets: 65 | - images/error_image.png 66 | 67 | # An image asset can refer to one or more resolution-specific "variants", see 68 | # https://flutter.dev/assets-and-images/#resolution-aware. 69 | 70 | # For details regarding adding assets from package dependencies, see 71 | # https://flutter.dev/assets-and-images/#from-packages 72 | 73 | # To add custom fonts to your application, add a fonts section here, 74 | # in this "flutter" section. Each entry in this list should have a 75 | # "family" key with the font family name, and a "fonts" key with a 76 | # list giving the asset and other descriptors for the font. For 77 | # example: 78 | fonts: 79 | - family: iron 80 | fonts: 81 | - asset: fonts/ironclad.ttf 82 | - family: metropolis 83 | fonts: 84 | - asset: fonts/metropolis.otf 85 | # For details regarding fonts from package dependencies, 86 | # see https://flutter.dev/custom-fonts/#from-packages 87 | -------------------------------------------------------------------------------- /remote/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | .idea/ 8 | .vagrant/ 9 | .sconsign.dblite 10 | .svn/ 11 | 12 | *.swp 13 | profile 14 | 15 | DerivedData/ 16 | 17 | .generated/ 18 | 19 | *.pbxuser 20 | *.mode1v3 21 | *.mode2v3 22 | *.perspectivev3 23 | 24 | !default.pbxuser 25 | !default.mode1v3 26 | !default.mode2v3 27 | !default.perspectivev3 28 | 29 | xcuserdata 30 | 31 | *.moved-aside 32 | 33 | *.pyc 34 | *sync/ 35 | Icon? 36 | .tags* 37 | 38 | build/ 39 | .android/ 40 | .ios/ 41 | .flutter-plugins 42 | .flutter-plugins-dependencies 43 | 44 | # Symbolication related 45 | app.*.symbols 46 | 47 | # Obfuscation related 48 | app.*.map.json 49 | -------------------------------------------------------------------------------- /remote/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6 8 | channel: stable 9 | 10 | project_type: module 11 | -------------------------------------------------------------------------------- /remote/README.md: -------------------------------------------------------------------------------- 1 | # remote 2 | 3 | A new flutter module project. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.dev/). 9 | 10 | For instructions integrating Flutter modules to your existing applications, 11 | see the [add-to-app documentation](https://flutter.dev/docs/development/add-to-app). 12 | -------------------------------------------------------------------------------- /remote/lib/datasource/movies_shows_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:remote/model/cast_request.dart'; 2 | import 'package:remote/model/details_request.dart'; 3 | import 'package:remote/model/genres_request.dart'; 4 | import 'package:remote/model/movies_shows_genre_request.dart'; 5 | import 'package:remote/model/page_request.dart'; 6 | import 'package:remote/model/person_credits_request.dart'; 7 | import 'package:remote/model/person_info_request.dart'; 8 | import 'package:remote/model/movies_shows_request.dart'; 9 | import 'package:remote/model/search_request.dart'; 10 | import 'package:remote/model/trailer_request.dart'; 11 | import 'package:remote/model/trending_request.dart'; 12 | 13 | abstract class MoviesShowsDataSource { 14 | 15 | Future getConfig(); 16 | Future getTrending(TrendingRequest request); 17 | Future getTrendingPeople(TrendingRequest request); 18 | Future getDetails(DetailsRequest request); 19 | Future getTrailer(TrailerRequest request); 20 | Future getCast(CastRequest request); 21 | Future getPersonInfo(PersonInfoRequest request); 22 | Future getPersonCredits(PersonCreditsRequest request); 23 | Future getCurrentPlayingMovies(PageRequest request); 24 | Future getCurrentPlayingShows(PageRequest request); 25 | Future getPopularMoviesShows(MoviesShowsRequest request); 26 | Future getLatestMoviesShows(MoviesShowsRequest request); 27 | Future getTopRatedMoviesShows(MoviesShowsRequest request); 28 | Future getUpcomingMovies(PageRequest request); 29 | Future getAiringTodayShows(PageRequest request); 30 | Future getMoviesShowsByGenre(MoviesShowsGenreRequest request); 31 | Future getGenres(GenresRequest request); 32 | Future searchMoviesShows(SearchRequest request); 33 | } -------------------------------------------------------------------------------- /remote/lib/di/di.config.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | // ************************************************************************** 4 | // InjectableConfigGenerator 5 | // ************************************************************************** 6 | 7 | import 'package:get_it/get_it.dart' as _i1; 8 | import 'package:injectable/injectable.dart' as _i2; 9 | 10 | import '../datasource/movies_shows_data_source.dart' as _i3; 11 | import '../datasource/movies_shows_data_source_impl.dart' 12 | as _i4; // ignore_for_file: unnecessary_lambdas 13 | 14 | // ignore_for_file: lines_longer_than_80_chars 15 | /// initializes the registration of provided dependencies inside of [GetIt] 16 | _i1.GetIt $initRemoteGetIt(_i1.GetIt get, 17 | {String? environment, _i2.EnvironmentFilter? environmentFilter}) { 18 | final gh = _i2.GetItHelper(get, environment, environmentFilter); 19 | gh.singleton<_i3.MoviesShowsDataSource>(_i4.MoviesShowsDataSourceImpl()); 20 | return get; 21 | } 22 | -------------------------------------------------------------------------------- /remote/lib/di/di.dart: -------------------------------------------------------------------------------- 1 | import 'package:injectable/injectable.dart'; 2 | import 'package:remote/di/di.config.dart'; 3 | 4 | @InjectableInit( 5 | initializerName: r'$initRemoteGetIt' 6 | ) 7 | Future configureRemoteInjection(final getIt) async => $initRemoteGetIt(getIt); -------------------------------------------------------------------------------- /remote/lib/http_client.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:http/http.dart' as http; 3 | import 'package:remote/util/http_util.dart'; 4 | 5 | class HttpClient { 6 | final bearer = 7 | 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI1MzRjNDliM2EwOWUzNzMwM2YxNmJmMjQxNDMyOTIyZCIsInN1YiI6IjYwM2E5M2E5YzJmZjNkMDA1MjA2MzIwZCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.o6T32zw2hIBReqzSDx7hmBRsjUdma-IyTCY7bm-1lCM'; 8 | 9 | Future get({required String url}) async { 10 | var response = await http.get(Uri.parse(url), headers: _getHeaders()); 11 | return HttpUtil.getResponse(response); 12 | } 13 | 14 | Map _getHeaders() { 15 | final headers = {}; 16 | headers[HttpHeaders.authorizationHeader] = 'Bearer $bearer'; 17 | return headers; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /remote/lib/model/cast_request.dart: -------------------------------------------------------------------------------- 1 | class CastRequest { 2 | String type; 3 | double id; 4 | 5 | CastRequest(this.type, this.id); 6 | } -------------------------------------------------------------------------------- /remote/lib/model/details_request.dart: -------------------------------------------------------------------------------- 1 | class DetailsRequest { 2 | String type; 3 | double id; 4 | 5 | DetailsRequest({required this.type, required this.id}); 6 | } 7 | -------------------------------------------------------------------------------- /remote/lib/model/genres_request.dart: -------------------------------------------------------------------------------- 1 | class GenresRequest { 2 | String type; 3 | 4 | GenresRequest({required this.type}); 5 | } 6 | -------------------------------------------------------------------------------- /remote/lib/model/movies_shows_genre_request.dart: -------------------------------------------------------------------------------- 1 | class MoviesShowsGenreRequest { 2 | String type; 3 | int genreId; 4 | int page; 5 | 6 | MoviesShowsGenreRequest( 7 | {required this.type, required this.genreId, required this.page}); 8 | } 9 | -------------------------------------------------------------------------------- /remote/lib/model/movies_shows_request.dart: -------------------------------------------------------------------------------- 1 | class MoviesShowsRequest { 2 | String type; 3 | int page; 4 | 5 | MoviesShowsRequest({required this.type, required this.page}); 6 | } 7 | -------------------------------------------------------------------------------- /remote/lib/model/page_request.dart: -------------------------------------------------------------------------------- 1 | class PageRequest { 2 | int page; 3 | 4 | PageRequest({required this.page}); 5 | } 6 | -------------------------------------------------------------------------------- /remote/lib/model/person_credits_request.dart: -------------------------------------------------------------------------------- 1 | class PersonCreditsRequest { 2 | double id; 3 | 4 | PersonCreditsRequest({required this.id}); 5 | } 6 | -------------------------------------------------------------------------------- /remote/lib/model/person_info_request.dart: -------------------------------------------------------------------------------- 1 | class PersonInfoRequest { 2 | double id; 3 | 4 | PersonInfoRequest({required this.id}); 5 | } -------------------------------------------------------------------------------- /remote/lib/model/search_request.dart: -------------------------------------------------------------------------------- 1 | class SearchRequest { 2 | String searchTerm; 3 | 4 | SearchRequest({required this.searchTerm}); 5 | } 6 | -------------------------------------------------------------------------------- /remote/lib/model/trailer_request.dart: -------------------------------------------------------------------------------- 1 | class TrailerRequest { 2 | String type; 3 | double id; 4 | 5 | TrailerRequest(this.type, this.id); 6 | } 7 | -------------------------------------------------------------------------------- /remote/lib/model/trending_request.dart: -------------------------------------------------------------------------------- 1 | class TrendingRequest { 2 | String type; 3 | 4 | TrendingRequest({required this.type}); 5 | } -------------------------------------------------------------------------------- /remote/lib/util/api_constants.dart: -------------------------------------------------------------------------------- 1 | class ApiConstants { 2 | static const base_url = 'https://api.themoviedb.org/3'; 3 | static const http_success = 200; 4 | } -------------------------------------------------------------------------------- /remote/lib/util/http_util.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:http/http.dart'; 4 | import 'package:remote/util/api_constants.dart'; 5 | 6 | class HttpUtil { 7 | 8 | static dynamic getResponse(Response response) { 9 | switch(response.statusCode) { 10 | case ApiConstants.http_success: 11 | return _getSuccessResponse(response); 12 | default: 13 | return Exception('Remote Error'); 14 | } 15 | } 16 | 17 | static dynamic _getSuccessResponse(Response response) { 18 | final _responseJson = json.decode(response.body); 19 | print('Response: $_responseJson'); 20 | return _responseJson; 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /remote/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: remote 2 | description: A new flutter module project. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | # 15 | # This version is used _only_ for the Runner app, which is used if you just do 16 | # a `flutter run` or a `flutter make-host-app-editable`. It has no impact 17 | # on any other native host app that you embed your Flutter project into. 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | 27 | # The following adds the Cupertino Icons font to your application. 28 | # Use with the CupertinoIcons class for iOS style icons. 29 | cupertino_icons: ^1.0.0 30 | http: ^0.13.1 31 | injectable: ^1.2.2 32 | get_it: ^6.0.0 33 | 34 | dev_dependencies: 35 | flutter_test: 36 | sdk: flutter 37 | injectable_generator: 1.2.2 38 | build_runner: 1.12.2 39 | 40 | # For information on the generic Dart part of this file, see the 41 | # following page: https://dart.dev/tools/pub/pubspec 42 | 43 | flutter: 44 | # The following line ensures that the Material Icons font is 45 | # included with your application, so that you can use the icons in 46 | # the material Icons class. 47 | uses-material-design: true 48 | 49 | # To add Flutter specific assets to your application, add an assets section, 50 | # like this: 51 | # assets: 52 | # - images/a_dot_burr.jpeg 53 | # - images/a_dot_ham.jpeg 54 | 55 | # An image asset can refer to one or more resolution-specific "variants", see 56 | # https://flutter.dev/assets-and-images/#resolution-aware. 57 | 58 | # For details regarding adding assets from package dependencies, see 59 | # https://flutter.dev/assets-and-images/#from-packages 60 | 61 | # To add Flutter specific custom fonts to your application, add a fonts 62 | # section here, in this "flutter" section. Each entry in this list should 63 | # have a "family" key with the font family name, and a "fonts" key with a 64 | # list giving the asset and other descriptors for the font. For 65 | # example: 66 | # fonts: 67 | # - family: Schyler 68 | # fonts: 69 | # - asset: fonts/Schyler-Regular.ttf 70 | # - asset: fonts/Schyler-Italic.ttf 71 | # style: italic 72 | # - family: Trajan Pro 73 | # fonts: 74 | # - asset: fonts/TrajanPro.ttf 75 | # - asset: fonts/TrajanPro_Bold.ttf 76 | # weight: 700 77 | # 78 | # For details regarding fonts from package dependencies, 79 | # see https://flutter.dev/custom-fonts/#from-packages 80 | 81 | 82 | # This section identifies your Flutter project as a module meant for 83 | # embedding in a native host app. These identifiers should _not_ ordinarily 84 | # be changed after generation - they are used to ensure that the tooling can 85 | # maintain consistency when adding or modifying assets and plugins. 86 | # They also do not have any bearing on your native host application's 87 | # identifiers, which may be completely independent or the same as these. 88 | module: 89 | androidX: true 90 | androidPackage: com.ruben.funbox.remote 91 | iosBundleIdentifier: com.ruben.funbox.remote 92 | -------------------------------------------------------------------------------- /remote/remote.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /remote/remote_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /screenshots/home.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/screenshots/home.jpg -------------------------------------------------------------------------------- /screenshots/movie_show_details.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/screenshots/movie_show_details.jpg -------------------------------------------------------------------------------- /screenshots/movie_show_filters.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/screenshots/movie_show_filters.jpg -------------------------------------------------------------------------------- /screenshots/movie_show_search.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/screenshots/movie_show_search.jpg -------------------------------------------------------------------------------- /screenshots/movies.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/screenshots/movies.jpg -------------------------------------------------------------------------------- /screenshots/person_details.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/screenshots/person_details.jpg -------------------------------------------------------------------------------- /screenshots/tv_show_details.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/screenshots/tv_show_details.jpg -------------------------------------------------------------------------------- /screenshots/tv_shows.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubenquadros/Flutter-BLoC-Clean-Architecture-Example/748a999fd828e7b71e2fcc9c567cb62cbb260c1f/screenshots/tv_shows.jpg --------------------------------------------------------------------------------