├── lavender_serverCode ├── .gitignore ├── package.json ├── routers │ ├── anime_list.js │ ├── featuredBanner.js │ ├── Animated_movies.js │ ├── action_series.js │ ├── comming_soon.js │ ├── horror_series.js │ ├── animated_series.js │ ├── action_movie.js │ ├── horror_movies.js │ ├── trending.js │ ├── new_arrivals.js │ └── indian_channel_list.js └── server.js ├── lavender_app ├── ios │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner │ │ ├── Runner-Bridging-Header.h │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ ├── 100.png │ │ │ │ ├── 114.png │ │ │ │ ├── 120.png │ │ │ │ ├── 128.png │ │ │ │ ├── 144.png │ │ │ │ ├── 152.png │ │ │ │ ├── 16.png │ │ │ │ ├── 167.png │ │ │ │ ├── 172.png │ │ │ │ ├── 180.png │ │ │ │ ├── 196.png │ │ │ │ ├── 20.png │ │ │ │ ├── 216.png │ │ │ │ ├── 256.png │ │ │ │ ├── 29.png │ │ │ │ ├── 32.png │ │ │ │ ├── 40.png │ │ │ │ ├── 48.png │ │ │ │ ├── 50.png │ │ │ │ ├── 512.png │ │ │ │ ├── 55.png │ │ │ │ ├── 57.png │ │ │ │ ├── 58.png │ │ │ │ ├── 60.png │ │ │ │ ├── 64.png │ │ │ │ ├── 72.png │ │ │ │ ├── 76.png │ │ │ │ ├── 80.png │ │ │ │ ├── 87.png │ │ │ │ ├── 88.png │ │ │ │ ├── 1024.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── .gitignore ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ └── Icon-512.png │ ├── manifest.json │ └── index.html ├── android │ ├── gradle.properties │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values-night │ │ │ │ │ │ └── styles.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── example │ │ │ │ │ │ └── lavender │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── settings.gradle │ └── build.gradle ├── github_assets │ └── icon.png ├── assets │ └── fonts │ │ ├── Mukta-Bold.ttf │ │ ├── Mukta-Light.ttf │ │ ├── Mukta-Medium.ttf │ │ ├── Mukta-Regular.ttf │ │ ├── Mukta-SemiBold.ttf │ │ ├── Mukta-ExtraBold.ttf │ │ └── Mukta-ExtraLight.ttf ├── .metadata ├── lib │ ├── utils │ │ ├── network_constants.dart │ │ └── constants.dart │ ├── presentation │ │ ├── bloc │ │ │ ├── home_page_bloc │ │ │ │ ├── homepage_event.dart │ │ │ │ ├── homepage_state.dart │ │ │ │ └── homepage_bloc.dart │ │ │ ├── channel_page_bloc │ │ │ │ ├── channelpage_event.dart │ │ │ │ ├── channelpage_state.dart │ │ │ │ └── channelpage_bloc.dart │ │ │ ├── movie_list_page_bloc │ │ │ │ ├── movielistpage_event.dart │ │ │ │ ├── movielistpage_state.dart │ │ │ │ └── movielistpage_bloc.dart │ │ │ └── series_list_page │ │ │ │ ├── serieslistpage_event.dart │ │ │ │ ├── serieslistpage_state.dart │ │ │ │ └── serieslistpage_bloc.dart │ │ ├── widgets │ │ │ ├── channel_card.dart │ │ │ ├── widget_information_box.dart │ │ │ ├── Grid_Card.dart │ │ │ ├── categories_widget.dart │ │ │ ├── comming_soon_banner.dart │ │ │ ├── error_widget.dart │ │ │ ├── series_season_display_card.dart │ │ │ ├── list_screen.dart │ │ │ ├── search_bar.dart │ │ │ ├── horizontal_items_list.dart │ │ │ ├── channel_screen.dart │ │ │ └── home_screen_banner.dart │ │ └── pages │ │ │ ├── splash_screen.dart │ │ │ ├── series │ │ │ ├── series_categories_page.dart │ │ │ ├── series_list_page.dart │ │ │ ├── season_detail_page.dart │ │ │ ├── series_detail_page.dart │ │ │ └── episode_detail_page.dart │ │ │ ├── movies │ │ │ ├── movies_categories_page.dart │ │ │ ├── movies_list_page.dart │ │ │ └── movie_detail_page.dart │ │ │ ├── base_screen.dart │ │ │ ├── view_media_page.dart │ │ │ ├── channels │ │ │ └── channel_page.dart │ │ │ └── home_page.dart │ ├── main.dart │ ├── data │ │ ├── channels │ │ │ ├── language.dart │ │ │ └── channel.dart │ │ ├── comming_soon │ │ │ └── comming_soon.dart │ │ ├── movies │ │ │ ├── movies.dart │ │ │ └── movies_categories.dart │ │ └── series │ │ │ ├── episode.dart │ │ │ ├── series.dart │ │ │ ├── seasons.dart │ │ │ └── series_categories.dart │ └── domain │ │ └── repositories │ │ └── network_repo.dart ├── .gitignore ├── test │ └── widget_test.dart ├── pubspec.yaml ├── README.md └── pubspec.lock ├── github_assets └── Lavender.png └── README.md /lavender_serverCode/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | /node_modules -------------------------------------------------------------------------------- /lavender_app/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /lavender_app/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /github_assets/Lavender.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/github_assets/Lavender.png -------------------------------------------------------------------------------- /lavender_app/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/web/favicon.png -------------------------------------------------------------------------------- /lavender_app/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /lavender_app/github_assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/github_assets/icon.png -------------------------------------------------------------------------------- /lavender_app/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/web/icons/Icon-192.png -------------------------------------------------------------------------------- /lavender_app/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/web/icons/Icon-512.png -------------------------------------------------------------------------------- /lavender_app/assets/fonts/Mukta-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/assets/fonts/Mukta-Bold.ttf -------------------------------------------------------------------------------- /lavender_app/assets/fonts/Mukta-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/assets/fonts/Mukta-Light.ttf -------------------------------------------------------------------------------- /lavender_app/assets/fonts/Mukta-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/assets/fonts/Mukta-Medium.ttf -------------------------------------------------------------------------------- /lavender_app/assets/fonts/Mukta-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/assets/fonts/Mukta-Regular.ttf -------------------------------------------------------------------------------- /lavender_app/assets/fonts/Mukta-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/assets/fonts/Mukta-SemiBold.ttf -------------------------------------------------------------------------------- /lavender_app/assets/fonts/Mukta-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/assets/fonts/Mukta-ExtraBold.ttf -------------------------------------------------------------------------------- /lavender_app/assets/fonts/Mukta-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/assets/fonts/Mukta-ExtraLight.ttf -------------------------------------------------------------------------------- /lavender_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /lavender_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /lavender_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png -------------------------------------------------------------------------------- /lavender_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lavender_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hritikchaurasia/Lavender/HEAD/lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /lavender_app/android/app/src/main/kotlin/com/example/lavender/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.lavender 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /lavender_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lavender_app/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lavender_app/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.7-all.zip 7 | -------------------------------------------------------------------------------- /lavender_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lavender_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lavender_app/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 | -------------------------------------------------------------------------------- /lavender_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lavender_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lavender_app/.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: 8962f6dc68ec8e2206ac2fa874da4a453856c7d3 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /lavender_app/lib/utils/network_constants.dart: -------------------------------------------------------------------------------- 1 | 2 | class NetworkConstants{ 3 | 4 | //api constant 5 | static const baseUrl = "https://lavenderwebapp.herokuapp.com/"; 6 | static const token = 7 | 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJIcml0aWsiLCJuYW1lIjoiWW91d2lsbG5ldmVyZ2V0aXQiLCJpYXQiOjE1MTYyMzkwMjJ9.6PRPWzmu_or76BASRLuP59ALvgWdQ8viGM9aThRojyY'; 8 | 9 | } -------------------------------------------------------------------------------- /lavender_app/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lavender_app/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/home_page_bloc/homepage_event.dart: -------------------------------------------------------------------------------- 1 | part of 'homepage_bloc.dart'; 2 | 3 | abstract class HomePageEvent extends Equatable { 4 | const HomePageEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class GetHomePageData extends HomePageEvent { 11 | const GetHomePageData(); 12 | 13 | @override 14 | List get props => []; 15 | } 16 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/channel_page_bloc/channelpage_event.dart: -------------------------------------------------------------------------------- 1 | part of 'channelpage_bloc.dart'; 2 | 3 | abstract class ChannelPageEvent extends Equatable { 4 | const ChannelPageEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class GetChannelListData extends ChannelPageEvent { 11 | const GetChannelListData(); 12 | 13 | @override 14 | List get props => []; 15 | } 16 | -------------------------------------------------------------------------------- /lavender_app/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 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/movie_list_page_bloc/movielistpage_event.dart: -------------------------------------------------------------------------------- 1 | part of 'movielistpage_bloc.dart'; 2 | 3 | abstract class MovieListPageEvent extends Equatable { 4 | const MovieListPageEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class GetMovieListBaseOnCategory extends MovieListPageEvent { 11 | final String categoryUrl; 12 | 13 | const GetMovieListBaseOnCategory({@required this.categoryUrl}); 14 | 15 | @override 16 | List get props => [categoryUrl]; 17 | } 18 | -------------------------------------------------------------------------------- /lavender_app/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 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/series_list_page/serieslistpage_event.dart: -------------------------------------------------------------------------------- 1 | part of 'serieslistpage_bloc.dart'; 2 | 3 | abstract class SeriesListPageEvent extends Equatable { 4 | const SeriesListPageEvent(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | 11 | class GetSeriesListBaseOnCategory extends SeriesListPageEvent { 12 | final String categoryUrl; 13 | 14 | const GetSeriesListBaseOnCategory({@required this.categoryUrl}); 15 | 16 | @override 17 | List get props => [categoryUrl]; 18 | } 19 | -------------------------------------------------------------------------------- /lavender_app/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /lavender_app/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /lavender_app/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lavender", 3 | "short_name": "lavender", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /lavender_app/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 | -------------------------------------------------------------------------------- /lavender_app/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 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 | -------------------------------------------------------------------------------- /lavender_serverCode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lavender", 3 | "version": "1.0.0", 4 | "description": "hritik35@outlook.com\r Hritik@123", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node server.js", 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "dev": "nodemon server.js" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "cors": "^2.8.5", 15 | "express": "^4.17.1" 16 | }, 17 | "devDependencies": { 18 | "nodemon": "^2.0.7" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/Hritik35/lavender_serverCode.git" 23 | }, 24 | "bugs": { 25 | "url": "https://github.com/Hritik35/lavender_serverCode/issues" 26 | }, 27 | "homepage": "https://github.com/Hritik35/lavender_serverCode#readme" 28 | } 29 | -------------------------------------------------------------------------------- /lavender_serverCode/routers/anime_list.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_animeList = [ 5 | { 6 | "name":"Rent a girlfriend", 7 | "logo":"https://upload.wikimedia.org/wikipedia/pt/d/de/Kanojo%2C_Okarishimasu_poster.jpg", 8 | "type":"m38u", 9 | "url":"https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8" 10 | }, 11 | 12 | ] ; 13 | 14 | 15 | 16 | router.get('/', async (req,res) => { 17 | if(req.Auth){ 18 | try { 19 | res.status('200').send(resJson_animeList); 20 | } catch (error) { 21 | res.status('500').send('Server error'); 22 | } 23 | 24 | } 25 | else{ 26 | res.status('400').send('Auth fail'); 27 | } 28 | 29 | 30 | }); 31 | 32 | 33 | module.exports = router; -------------------------------------------------------------------------------- /lavender_serverCode/routers/featuredBanner.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_featuredBanner = { 5 | 6 | "name":"Godzilla vs Kong(Hindi audio)", 7 | "logo":"https://images-na.ssl-images-amazon.com/images/I/81SAqNnNlfL._AC_SL1500_.jpg", 8 | "type":"m38u", 9 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 10 | 11 | } ; 12 | 13 | 14 | 15 | router.get('/', async (req,res) => { 16 | if(req.Auth){ 17 | try { 18 | res.status('200').send(resJson_featuredBanner); 19 | } catch (error) { 20 | res.status('500').send('Server error'); 21 | } 22 | 23 | } 24 | else{ 25 | res.status('400').send('Auth fail'); 26 | } 27 | 28 | 29 | }); 30 | 31 | 32 | module.exports = router; -------------------------------------------------------------------------------- /lavender_app/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lavender_app/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | 48 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/channel_page_bloc/channelpage_state.dart: -------------------------------------------------------------------------------- 1 | part of 'channelpage_bloc.dart'; 2 | 3 | abstract class ChannelPageState extends Equatable { 4 | const ChannelPageState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class ChannelPageLoadingState extends ChannelPageState { 11 | const ChannelPageLoadingState(); 12 | 13 | @override 14 | List get props => []; 15 | } 16 | 17 | class ChannelPageLoadedState extends ChannelPageState { 18 | final List channelList; 19 | const ChannelPageLoadedState({@required this.channelList}); 20 | 21 | @override 22 | List get props => [channelList]; 23 | } 24 | 25 | class ChannelPageNoInternetState extends ChannelPageState { 26 | const ChannelPageNoInternetState(); 27 | 28 | @override 29 | List get props => []; 30 | } 31 | 32 | class ChannelPageErrorState extends ChannelPageState { 33 | const ChannelPageErrorState(); 34 | 35 | @override 36 | List get props => []; 37 | } 38 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/movie_list_page_bloc/movielistpage_state.dart: -------------------------------------------------------------------------------- 1 | part of 'movielistpage_bloc.dart'; 2 | 3 | abstract class MovieListPageState extends Equatable { 4 | const MovieListPageState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class MovieListPageLoadingState extends MovieListPageState { 11 | const MovieListPageLoadingState(); 12 | 13 | @override 14 | List get props => []; 15 | } 16 | 17 | class MovieListPageLoadedState extends MovieListPageState { 18 | final List moviesList; 19 | const MovieListPageLoadedState({@required this.moviesList}); 20 | 21 | @override 22 | List get props => [moviesList]; 23 | } 24 | 25 | class MovieListPageNoInternetState extends MovieListPageState { 26 | const MovieListPageNoInternetState(); 27 | 28 | @override 29 | List get props => []; 30 | } 31 | 32 | class MovieListPageErrorState extends MovieListPageState { 33 | const MovieListPageErrorState(); 34 | 35 | @override 36 | List get props => []; 37 | } 38 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/channel_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ChannelCard extends StatelessWidget { 4 | final String channelName; 5 | final String channelLogo; 6 | final Size size; 7 | 8 | const ChannelCard( 9 | {Key key, 10 | @required this.channelName, 11 | @required this.channelLogo, 12 | @required this.size}) 13 | : super(key: key); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Container( 18 | height: 100.0, 19 | width: 100.0, 20 | child: Column( 21 | mainAxisSize: MainAxisSize.min, 22 | children: [ 23 | Expanded( 24 | child: Container( 25 | decoration: BoxDecoration( 26 | borderRadius: BorderRadius.circular(20.0), 27 | image: DecorationImage( 28 | image: NetworkImage(channelLogo), fit: BoxFit.fill)), 29 | ), 30 | ), 31 | ], 32 | ), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lavender_serverCode/routers/Animated_movies.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_animationMovieList = [ 5 | { 6 | "name":"Panda Vs Aliens(720p)", 7 | "logo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg", 8 | "type":"m38u", 9 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 10 | "language":"English", 11 | "description":"A group of aliens seek out to conquer new worlds and take particular notice of Earth, after seeing satellite broadcasts of TV shows of a powerful panda, Pandy." 12 | }, 13 | 14 | ] ; 15 | 16 | 17 | 18 | router.get('/', async (req,res) => { 19 | if(req.Auth){ 20 | try { 21 | res.status('200').send(resJson_animationMovieList); 22 | } catch (error) { 23 | res.status('500').send('Server error'); 24 | } 25 | 26 | } 27 | else{ 28 | res.status('400').send('Auth fail'); 29 | } 30 | 31 | 32 | }); 33 | 34 | 35 | module.exports = router; -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/series_list_page/serieslistpage_state.dart: -------------------------------------------------------------------------------- 1 | part of 'serieslistpage_bloc.dart'; 2 | 3 | abstract class SeriesListPageState extends Equatable { 4 | const SeriesListPageState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | 11 | class SeriesListPageLoadingState extends SeriesListPageState { 12 | const SeriesListPageLoadingState(); 13 | 14 | @override 15 | List get props => []; 16 | } 17 | 18 | class SeriesListPageLoadedState extends SeriesListPageState { 19 | final List seriesList; 20 | const SeriesListPageLoadedState({@required this.seriesList}); 21 | 22 | @override 23 | List get props => [seriesList]; 24 | } 25 | 26 | class SeriesListPageNoInternetState extends SeriesListPageState { 27 | const SeriesListPageNoInternetState(); 28 | 29 | @override 30 | List get props => []; 31 | } 32 | 33 | class SeriesListPageErrorState extends SeriesListPageState { 34 | const SeriesListPageErrorState(); 35 | 36 | @override 37 | List get props => []; 38 | } 39 | -------------------------------------------------------------------------------- /lavender_app/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lavender_app/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/channel_page_bloc/channelpage_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:bloc/bloc.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:flutter/foundation.dart'; 7 | 8 | import '../../../data/channels/channel.dart'; 9 | import '../../../domain/repositories/network_repo.dart'; 10 | 11 | part 'channelpage_event.dart'; 12 | part 'channelpage_state.dart'; 13 | 14 | class ChannelPageBloc extends Bloc { 15 | ChannelPageBloc() : super(ChannelPageLoadingState()); 16 | 17 | @override 18 | Stream mapEventToState( 19 | ChannelPageEvent event, 20 | ) async* { 21 | if (event is GetChannelListData) { 22 | yield ChannelPageLoadingState(); 23 | try { 24 | final List channelList = 25 | await NetworkRepo().indianChannelList(); 26 | yield ChannelPageLoadedState(channelList: channelList); 27 | } on IOException { 28 | yield ChannelPageNoInternetState(); 29 | } catch (e) { 30 | print(e.toString()); 31 | yield ChannelPageErrorState(); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lavender_app/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:lavender/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /lavender_app/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: lavender 2 | description: A new Flutter project. 3 | 4 | publish_to: 'none' 5 | 6 | version: 1.0.0+1 7 | 8 | environment: 9 | sdk: ">=2.7.0 <3.0.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | cupertino_icons: ^1.0.2 15 | equatable: ^2.0.0 16 | flutter_bloc: ^7.0.0 17 | http: ^0.12.2 18 | yoyo_player: ^0.1.0 19 | lottie: ^1.0.1 20 | 21 | 22 | dev_dependencies: 23 | flutter_test: 24 | sdk: flutter 25 | 26 | flutter: 27 | 28 | uses-material-design: true 29 | 30 | assets: 31 | - assets/images/ 32 | 33 | fonts: 34 | - family: Mukta 35 | fonts: 36 | - asset: assets/fonts/Mukta-ExtraBold.ttf 37 | weight: 800 38 | - asset: assets/fonts/Mukta-Bold.ttf 39 | weight: 700 40 | - asset: assets/fonts/Mukta-SemiBold.ttf 41 | weight: 600 42 | - asset: assets/fonts/Mukta-Regular.ttf 43 | weight: 500 44 | - asset: assets/fonts/Mukta-Medium.ttf 45 | weight: 400 46 | - asset: assets/fonts/Mukta-Light.ttf 47 | weight: 300 48 | - asset: assets\fonts\Mukta-ExtraLight.ttf 49 | weight: 200 50 | 51 | 52 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/movie_list_page_bloc/movielistpage_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:bloc/bloc.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:flutter/foundation.dart'; 7 | 8 | import '../../../data/movies/movies.dart'; 9 | import '../../../domain/repositories/network_repo.dart'; 10 | 11 | part 'movielistpage_event.dart'; 12 | part 'movielistpage_state.dart'; 13 | 14 | class MovieListPageBloc extends Bloc { 15 | MovieListPageBloc() : super(MovieListPageLoadingState()); 16 | 17 | @override 18 | Stream mapEventToState( 19 | MovieListPageEvent event, 20 | ) async* { 21 | yield MovieListPageLoadingState(); 22 | if (event is GetMovieListBaseOnCategory) { 23 | try { 24 | final List moviesList = 25 | await NetworkRepo().getMovieCategoryList(event.categoryUrl); 26 | yield MovieListPageLoadedState(moviesList: moviesList); 27 | } on IOException { 28 | yield MovieListPageNoInternetState(); 29 | } catch (e) { 30 | yield MovieListPageErrorState(); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/home_page_bloc/homepage_state.dart: -------------------------------------------------------------------------------- 1 | part of 'homepage_bloc.dart'; 2 | 3 | abstract class HomePageState extends Equatable { 4 | const HomePageState(); 5 | 6 | @override 7 | List get props => []; 8 | } 9 | 10 | class HomePageLoadingState extends HomePageState { 11 | const HomePageLoadingState(); 12 | 13 | @override 14 | List get props => []; 15 | } 16 | 17 | class HomePageLoadedState extends HomePageState { 18 | final List trendingList; 19 | final featuredBanner; 20 | final List newArrivals; 21 | final List commingSoonList; 22 | HomePageLoadedState({@required this.commingSoonList, 23 | @required this.featuredBanner, 24 | @required this.trendingList, 25 | @required this.newArrivals, 26 | }); 27 | @override 28 | List get props => [trendingList, trendingList, newArrivals , commingSoonList]; 29 | } 30 | 31 | class HomePageNoInternetState extends HomePageState { 32 | const HomePageNoInternetState(); 33 | 34 | @override 35 | List get props => []; 36 | } 37 | 38 | class HomePageErrorState extends HomePageState { 39 | const HomePageErrorState(); 40 | 41 | @override 42 | List get props => []; 43 | } 44 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/series_list_page/serieslistpage_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:bloc/bloc.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:flutter/foundation.dart'; 7 | 8 | import '../../../data/series/series.dart'; 9 | import '../../../domain/repositories/network_repo.dart'; 10 | 11 | part 'serieslistpage_event.dart'; 12 | part 'serieslistpage_state.dart'; 13 | 14 | class SeriesListPageBloc 15 | extends Bloc { 16 | SeriesListPageBloc() : super(SeriesListPageLoadingState()); 17 | 18 | @override 19 | Stream mapEventToState( 20 | SeriesListPageEvent event, 21 | ) async* { 22 | yield SeriesListPageLoadingState(); 23 | if (event is GetSeriesListBaseOnCategory) { 24 | try { 25 | final List seriesList = 26 | await NetworkRepo().getSeriesCategoryList(event.categoryUrl); 27 | yield SeriesListPageLoadedState(seriesList: seriesList); 28 | } on IOException { 29 | yield SeriesListPageNoInternetState(); 30 | } catch (e) { 31 | yield SeriesListPageErrorState(); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/widget_information_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../utils/constants.dart'; 4 | 5 | class WidgetInformationBox extends StatelessWidget { 6 | const WidgetInformationBox({ 7 | Key key, 8 | @required this.width, 9 | @required this.text, 10 | @required this.title, 11 | }) : super(key: key); 12 | 13 | final double width; 14 | final String title; 15 | final String text; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Container( 20 | width: width, 21 | padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 10.0), 22 | decoration: BoxDecoration( 23 | color: Colors.white.withOpacity(0.05), 24 | ), 25 | child: RichText( 26 | text: TextSpan( 27 | style: const TextStyle( 28 | fontSize: 15.0, 29 | color: whiteColor, 30 | ), 31 | children: [ 32 | TextSpan(text: title), 33 | TextSpan( 34 | text: text, 35 | style: const TextStyle( 36 | fontWeight: FontWeight.bold, 37 | ), 38 | ), 39 | ], 40 | ), 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lavender_app/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'presentation/pages/splash_screen.dart'; 4 | import 'utils/constants.dart'; 5 | 6 | void main() { 7 | runApp(MyApp()); 8 | } 9 | 10 | class MyApp extends StatelessWidget { 11 | const MyApp({Key key}) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return MaterialApp( 16 | debugShowCheckedModeBanner: false, 17 | themeMode: ThemeMode.dark, 18 | theme: ThemeData( 19 | fontFamily: 'Mukta', 20 | scaffoldBackgroundColor: backgroundColor, 21 | buttonColor: darkBlueColor, 22 | accentColor: whiteColor, 23 | iconTheme: IconThemeData(color: whiteColor), 24 | appBarTheme: AppBarTheme(backgroundColor: darkGreyColor), 25 | bottomNavigationBarTheme: 26 | BottomNavigationBarThemeData(backgroundColor: darkGreyColor), 27 | hintColor: whiteColor, 28 | elevatedButtonTheme: ElevatedButtonThemeData( 29 | style: ButtonStyle( 30 | backgroundColor: MaterialStateProperty.all(Colors.redAccent) 31 | ) 32 | ) 33 | ), 34 | title: 'lavender', 35 | home: SplashScreen(), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lavender_app/lib/data/channels/language.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | 5 | class Language { 6 | final String code; 7 | final String name; 8 | const Language({ 9 | @required this.code, 10 | @required this.name, 11 | }); 12 | 13 | Language copyWith({ 14 | String code, 15 | String name, 16 | }) { 17 | return Language( 18 | code: code ?? this.code, 19 | name: name ?? this.name, 20 | ); 21 | } 22 | 23 | Map toMap() { 24 | return { 25 | 'code': code, 26 | 'name': name, 27 | }; 28 | } 29 | 30 | factory Language.fromMap(Map map) { 31 | return Language( 32 | code: map['code'], 33 | name: map['name'], 34 | ); 35 | } 36 | 37 | String toJson() => json.encode(toMap()); 38 | 39 | factory Language.fromJson(String source) => Language.fromMap(json.decode(source)); 40 | 41 | @override 42 | String toString() => 'Language(code: $code, name: $name)'; 43 | 44 | @override 45 | bool operator ==(Object other) { 46 | if (identical(this, other)) return true; 47 | 48 | return other is Language && 49 | other.code == code && 50 | other.name == name; 51 | } 52 | 53 | @override 54 | int get hashCode => code.hashCode ^ name.hashCode; 55 | } -------------------------------------------------------------------------------- /lavender_app/lib/utils/constants.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | 3 | //colors 4 | const backgroundColor = const Color(0xff222831); 5 | const darkGreyColor = const Color(0xff393e46); 6 | const darkBlueColor = const Color(0xff00f2ff); 7 | const whiteColor = const Color(0xffeeeeee); 8 | 9 | 10 | //styles 11 | const logoTextStyle = const TextStyle( 12 | color: darkBlueColor, 13 | fontSize: 30.0, 14 | fontFamily: 'Mukta', 15 | fontWeight: FontWeight.w800); 16 | 17 | const channelStyle = const TextStyle( 18 | color: whiteColor, 19 | fontSize: 14.0, 20 | fontFamily: 'Mukta', 21 | fontWeight: FontWeight.w200); 22 | 23 | const listTitleStyle = 24 | const TextStyle(color: whiteColor, fontSize: 14.0, fontFamily: 'Mukta'); 25 | const commingSoonTitleStyle = 26 | const TextStyle(color: darkBlueColor, fontSize: 20.0, fontFamily: 'Mukta' , fontWeight: FontWeight.w600); 27 | 28 | 29 | 30 | //sizedboxes 31 | const sized5 = const SizedBox(height: 5.0); 32 | const sized10 = const SizedBox(height: 10.0); 33 | const sized20 = const SizedBox(height: 20.0); 34 | const sized30 = const SizedBox(height: 30.0); 35 | const sized40 = const SizedBox(height: 40.0); 36 | const sized50 = const SizedBox(height: 50.0); 37 | 38 | //search text names 39 | const String searchMovies = 'Enter Movie Name'; 40 | const String searchChannels = 'Enter Channel Name'; 41 | const String searchCategories = 'Enter Category Name'; 42 | -------------------------------------------------------------------------------- /lavender_serverCode/routers/action_series.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_actionSeriesList = [ 5 | { 6 | "name":"ekk", 7 | "logo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg", 8 | "description":"this is new series", 9 | "seasons":[ 10 | { 11 | "seasonName" : "season1", 12 | "seasonDescription":"this is first season", 13 | "seasonLogo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg", 14 | "episodes":[ 15 | { 16 | "episodeName":"episode1", 17 | "episodeDescription":"this is first episode" , 18 | "episodeUrl":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 19 | "episodeLogo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg" 20 | } 21 | ] 22 | 23 | } 24 | ], 25 | "language":"English" 26 | }, 27 | 28 | ] ; 29 | 30 | 31 | 32 | router.get('/', async (req,res) => { 33 | if(req.Auth){ 34 | try { 35 | res.status('200').send(resJson_actionSeriesList); 36 | } catch (error) { 37 | res.status('500').send('Server error'); 38 | } 39 | 40 | } 41 | else{ 42 | res.status('400').send('Auth fail'); 43 | } 44 | 45 | 46 | }); 47 | 48 | 49 | module.exports = router; -------------------------------------------------------------------------------- /lavender_serverCode/routers/comming_soon.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_CommingSoon = [ 5 | { 6 | 7 | "name":"Godzilla vs Kong(Hindi audio)", 8 | "logo":"https://images-na.ssl-images-amazon.com/images/I/81SAqNnNlfL._AC_SL1500_.jpg", 9 | "type":"m38u", 10 | "releaseDate":"21/06/2021", 11 | 12 | },{ 13 | 14 | "name":"Godzilla vs Kong(Hindi audio)", 15 | "logo":"https://images-na.ssl-images-amazon.com/images/I/81SAqNnNlfL._AC_SL1500_.jpg", 16 | "type":"m38u", 17 | "releaseDate":"21/06/2021", 18 | 19 | },{ 20 | 21 | "name":"Godzilla vs Kong(Hindi audio)", 22 | "logo":"https://images-na.ssl-images-amazon.com/images/I/81SAqNnNlfL._AC_SL1500_.jpg", 23 | "type":"m38u", 24 | "releaseDate":"21/06/2021", 25 | 26 | },{ 27 | 28 | "name":"Godzilla vs Kong(Hindi audio)", 29 | "logo":"https://images-na.ssl-images-amazon.com/images/I/81SAqNnNlfL._AC_SL1500_.jpg", 30 | "type":"m38u", 31 | "releaseDate":"21/06/2021", 32 | 33 | }, 34 | ] ; 35 | 36 | 37 | 38 | router.get('/', async (req,res) => { 39 | if(req.Auth){ 40 | try { 41 | res.status('200').send(resJson_CommingSoon); 42 | } catch (error) { 43 | res.status('500').send('Server error'); 44 | } 45 | 46 | } 47 | else{ 48 | res.status('400').send('Auth fail'); 49 | } 50 | 51 | 52 | }); 53 | 54 | 55 | module.exports = router; -------------------------------------------------------------------------------- /lavender_serverCode/routers/horror_series.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_horrorSeriesList = [ 5 | { 6 | "name":"ekk", 7 | "logo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg", 8 | "description":"this is new series", 9 | "seasons":[ 10 | { 11 | "seasonName" : "season1", 12 | "seasonDescription":"this is first season", 13 | "seasonLogo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg", 14 | "episodes":[ 15 | { 16 | "episodeName":"episode1", 17 | "episodeDescription":"this is first episode" , 18 | "episodeUrl":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 19 | "episodeLogo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg" 20 | } 21 | ] 22 | 23 | } 24 | ], 25 | "language":"English" 26 | }, 27 | 28 | ] ; 29 | 30 | 31 | 32 | router.get('/', async (req,res) => { 33 | if(req.Auth){ 34 | try { 35 | res.status('200').send(resJson_horrorSeriesList); 36 | } catch (error) { 37 | res.status('500').send('Server error'); 38 | } 39 | 40 | } 41 | else{ 42 | res.status('400').send('Auth fail'); 43 | } 44 | 45 | 46 | }); 47 | 48 | 49 | module.exports = router; -------------------------------------------------------------------------------- /lavender_serverCode/routers/animated_series.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_animatedSeriesList = [ 5 | { 6 | "name":"ekk", 7 | "logo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg", 8 | "description":"this is new series", 9 | "seasons":[ 10 | { 11 | "seasonName" : "season1", 12 | "seasonDescription":"this is first season", 13 | "seasonLogo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg", 14 | "episodes":[ 15 | { 16 | "episodeName":"episode1", 17 | "episodeDescription":"this is first episode" , 18 | "episodeUrl":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 19 | "episodeLogo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg" 20 | } 21 | ] 22 | 23 | } 24 | ], 25 | "language":"English" 26 | }, 27 | 28 | ] ; 29 | 30 | 31 | 32 | router.get('/', async (req,res) => { 33 | if(req.Auth){ 34 | try { 35 | res.status('200').send(resJson_animatedSeriesList); 36 | } catch (error) { 37 | res.status('500').send('Server error'); 38 | } 39 | 40 | } 41 | else{ 42 | res.status('400').send('Auth fail'); 43 | } 44 | 45 | 46 | }); 47 | 48 | 49 | module.exports = router; -------------------------------------------------------------------------------- /lavender_app/lib/data/comming_soon/comming_soon.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class CommingSoon { 4 | final String name; 5 | final String logo; 6 | final String releaseDate; 7 | 8 | const CommingSoon( 9 | this.name, 10 | this.logo, 11 | this.releaseDate, 12 | ); 13 | 14 | CommingSoon copyWith({ 15 | String name, 16 | String logo, 17 | String releaseDate, 18 | }) { 19 | return CommingSoon( 20 | name ?? this.name, 21 | logo ?? this.logo, 22 | releaseDate ?? this.releaseDate, 23 | ); 24 | } 25 | 26 | Map toMap() { 27 | return { 28 | 'name': name, 29 | 'logo': logo, 30 | 'releaseDate': releaseDate, 31 | }; 32 | } 33 | 34 | factory CommingSoon.fromMap(Map map) { 35 | return CommingSoon( 36 | map['name'], 37 | map['logo'], 38 | map['releaseDate'], 39 | ); 40 | } 41 | 42 | String toJson() => json.encode(toMap()); 43 | 44 | factory CommingSoon.fromJson(String source) => CommingSoon.fromMap(json.decode(source)); 45 | 46 | @override 47 | String toString() => 'CommingSoon(name: $name, logo: $logo, releaseDate: $releaseDate)'; 48 | 49 | @override 50 | bool operator ==(Object other) { 51 | if (identical(this, other)) return true; 52 | 53 | return other is CommingSoon && 54 | other.name == name && 55 | other.logo == logo && 56 | other.releaseDate == releaseDate; 57 | } 58 | 59 | @override 60 | int get hashCode => name.hashCode ^ logo.hashCode ^ releaseDate.hashCode; 61 | } 62 | -------------------------------------------------------------------------------- /lavender_serverCode/routers/action_movie.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_actionMoviesList = [ 5 | { 6 | "name":"Godzilla vs Kong(Hindi audio)", 7 | "logo":"https://images-na.ssl-images-amazon.com/images/I/81SAqNnNlfL._AC_SL1500_.jpg", 8 | "type":"m38u", 9 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 10 | "language":"Hindi", 11 | "description":"Godzilla vs. Kong is a 2021 American monster film directed by Adam Wingard. A sequel to Godzilla: King of the Monsters (2019) and Kong: Skull Island (2017), it is the fourth film in Legendary's MonsterVerse. It is also the 36th film in the Godzilla franchise, the 12th film in the King Kong franchise, and the fourth Godzilla film to be completely produced by a Hollywood studio. The film stars Alexander Skarsgård, Millie Bobby Brown, Rebecca Hall, Brian Tyree Henry, Shun Oguri, Eiza González, Julian Dennison, Lance Reddick, Kyle Chandler, and Demián Bichir. In the film, Kong clashes with Godzilla as humans lure the ape into the Hollow Earth to retrieve a power source for a weapon to stop Godzilla's mysterious rampages." 12 | }, 13 | 14 | 15 | ] ; 16 | 17 | 18 | 19 | router.get('/', async (req,res) => { 20 | if(req.Auth){ 21 | try { 22 | res.status('200').send(resJson_actionMoviesList); 23 | } catch (error) { 24 | res.status('500').send('Server error'); 25 | } 26 | 27 | } 28 | else{ 29 | res.status('400').send('Auth fail'); 30 | } 31 | 32 | 33 | }); 34 | 35 | 36 | module.exports = router; -------------------------------------------------------------------------------- /lavender_app/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | lavender 30 | 31 | 32 | 33 | 36 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/Grid_Card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | import '../../utils/constants.dart'; 5 | 6 | class GridCard extends StatelessWidget { 7 | final String name; 8 | 9 | final String logoUrl; 10 | 11 | const GridCard( 12 | {Key key, 13 | @required this.name, 14 | 15 | @required this.logoUrl}) 16 | : super(key: key); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Container( 21 | margin: const EdgeInsets.all(8.0), 22 | width: 200.0, 23 | height: 200.0, 24 | decoration: BoxDecoration( 25 | borderRadius: BorderRadius.circular(10.0), 26 | 27 | gradient: 28 | LinearGradient( 29 | begin: Alignment.topLeft, 30 | end: Alignment.bottomRight, 31 | colors: [darkBlueColor , darkGreyColor]), 32 | ), 33 | child: Column(children: [ 34 | Expanded( 35 | child: Container( 36 | decoration: BoxDecoration( 37 | borderRadius: BorderRadius.only( 38 | topLeft: Radius.circular(10.0), 39 | topRight: Radius.circular(10.0)), 40 | image: DecorationImage( 41 | image: NetworkImage( 42 | logoUrl, 43 | ), 44 | fit: BoxFit.cover, 45 | )), 46 | ), 47 | ), 48 | sized5, 49 | RichText( 50 | 51 | text: TextSpan( 52 | text: name, 53 | style: listTitleStyle 54 | )), 55 | sized5 56 | ]), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/categories_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../utils/constants.dart'; 4 | import 'Grid_Card.dart'; 5 | import 'search_bar.dart'; 6 | 7 | class CategoriesWidget extends StatelessWidget { 8 | final Function onSearchBarValueChangeFunction; 9 | final Function(String, String) onTapNavigate; 10 | final List categoriesList; 11 | 12 | const CategoriesWidget( 13 | {Key key, 14 | @required this.onSearchBarValueChangeFunction, 15 | @required this.categoriesList, 16 | @required this.onTapNavigate}) 17 | : super(key: key); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return ListView( 22 | children: [ 23 | sized10, 24 | SearchBar( 25 | searchHint: searchCategories, 26 | onchangeFunction: onSearchBarValueChangeFunction, 27 | ), 28 | sized10, 29 | GridView.builder( 30 | physics: NeverScrollableScrollPhysics(), 31 | shrinkWrap: true, 32 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 33 | crossAxisCount: 2, 34 | ), 35 | itemCount: categoriesList.length, 36 | itemBuilder: (context, index) { 37 | return GestureDetector( 38 | onTap: () => onTapNavigate(categoriesList[index].categoryUrl, 39 | categoriesList[index].categoryName), 40 | child: GridCard( 41 | name: categoriesList[index].categoryName, 42 | logoUrl: categoriesList[index].categoryLogo, 43 | ), 44 | ); 45 | }), 46 | ], 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lavender_app/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 | -------------------------------------------------------------------------------- /lavender_app/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 | lavender 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 | NSAppTransportSecurity 45 | 46 | NSAllowsArbitraryLoads 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/comming_soon_banner.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lavender/data/comming_soon/comming_soon.dart'; 3 | 4 | class CommingSoonBanner extends StatelessWidget { 5 | final Size size; 6 | final List commingSoonList; 7 | const CommingSoonBanner( 8 | {Key key, @required this.size, @required this.commingSoonList}) 9 | : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container( 14 | height: size.height * 0.25, 15 | child: Center( 16 | child: ListView.builder( 17 | scrollDirection: Axis.horizontal, 18 | physics: BouncingScrollPhysics(), 19 | itemCount: commingSoonList.length, 20 | itemBuilder: (context, index) { 21 | return Container( 22 | margin: const EdgeInsets.symmetric(horizontal:10.0), 23 | width: size.width * 0.8, 24 | height: size.height * 0.25, 25 | child: Center( 26 | child: Text(commingSoonList[index].name, 27 | style: const TextStyle( 28 | color: Colors.white, 29 | fontWeight: FontWeight.w600, 30 | fontSize: 24.0)), 31 | ), 32 | decoration: BoxDecoration( 33 | borderRadius: BorderRadius.circular(20.0), 34 | image: DecorationImage( 35 | image: NetworkImage(commingSoonList[index].logo), 36 | fit: BoxFit.cover, 37 | colorFilter: ColorFilter.mode( 38 | Colors.black.withOpacity(0.2), BlendMode.dstATop), 39 | ), 40 | ), 41 | ); 42 | }), 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lavender_app/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 30 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | defaultConfig { 36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 37 | applicationId "com.example.lavender" 38 | minSdkVersion 16 39 | targetSdkVersion 30 40 | versionCode flutterVersionCode.toInteger() 41 | versionName flutterVersionName 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 59 | } 60 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/error_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../utils/constants.dart'; 4 | 5 | class CustomeErrorWidget extends StatelessWidget { 6 | static const Padding errorButtonChild = const Padding( 7 | padding: const EdgeInsets.all(10.0), 8 | child: Text('Retry', 9 | style: TextStyle( 10 | color: whiteColor, fontSize: 20.0, fontWeight: FontWeight.w400))); 11 | 12 | final Function retryFunction; 13 | final String errorTitle; 14 | 15 | const CustomeErrorWidget( 16 | {Key key, @required this.retryFunction, @required this.errorTitle}) 17 | : super(key: key); 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | final Size size = MediaQuery.of(context).size; 22 | return Center( 23 | 24 | child: Container( 25 | decoration: BoxDecoration( 26 | color: darkGreyColor, borderRadius: BorderRadius.circular(20.0)), 27 | child: ConstrainedBox( 28 | constraints: BoxConstraints( 29 | minWidth: size.width *0.7, 30 | maxWidth: size.width *0.7, 31 | ), 32 | child: Column( 33 | mainAxisSize: MainAxisSize.min, 34 | mainAxisAlignment: MainAxisAlignment.center, 35 | children: [ 36 | sized30, 37 | Container( 38 | 39 | child: Text( 40 | errorTitle, 41 | style: TextStyle( 42 | color: whiteColor, 43 | fontSize: 25.0, 44 | fontWeight: FontWeight.w500), 45 | ), 46 | ), 47 | sized30, 48 | ElevatedButton( 49 | onPressed: retryFunction, 50 | child: errorButtonChild, 51 | ), 52 | sized30, 53 | ], 54 | ), 55 | ), 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/series_season_display_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lavender/data/series/episode.dart'; 3 | 4 | import '../../data/series/seasons.dart'; 5 | import '../../utils/constants.dart'; 6 | 7 | class SeriesSeasonDisplayCard extends StatelessWidget { 8 | final Seasons seasons; 9 | final Episode episode; 10 | const SeriesSeasonDisplayCard({ 11 | this.seasons, 12 | this.episode, 13 | }); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Container( 18 | color: darkGreyColor, 19 | padding: const EdgeInsets.all(8.0), 20 | child: Row( 21 | children: [ 22 | Container( 23 | height: 100.0, 24 | width: 100.0, 25 | decoration: BoxDecoration( 26 | borderRadius: BorderRadius.circular(20.0), 27 | image: DecorationImage( 28 | image: NetworkImage(seasons!=null ? seasons.seasonLogo: episode.episodeLogo), 29 | fit: BoxFit.cover)), 30 | ), 31 | const SizedBox( 32 | width: 10.0, 33 | ), 34 | Column( 35 | crossAxisAlignment: CrossAxisAlignment.start, 36 | children: [ 37 | Text( 38 | seasons!=null ? seasons.seasonName: episode.episodeName, 39 | style: TextStyle( 40 | color: whiteColor, 41 | fontWeight: FontWeight.w700, 42 | fontSize: 26.0), 43 | ), 44 | Text( 45 | seasons!=null ? seasons.seasonDescription: episode.episodeDescription, 46 | style: TextStyle( 47 | color: Colors.white54, 48 | fontWeight: FontWeight.w300, 49 | fontSize: 20.0), 50 | ), 51 | ], 52 | ), 53 | ], 54 | ), 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/splash_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lottie/lottie.dart'; 3 | 4 | import '../../utils/constants.dart'; 5 | import 'base_screen.dart'; 6 | 7 | class SplashScreen extends StatefulWidget { 8 | SplashScreen({Key key}) : super(key: key); 9 | 10 | @override 11 | _SplashScreenState createState() => _SplashScreenState(); 12 | } 13 | 14 | class _SplashScreenState extends State 15 | with SingleTickerProviderStateMixin { 16 | AnimationController _animationController; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _animationController = AnimationController(vsync: this); 22 | } 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | final double width = MediaQuery.of(context).size.width; 27 | return Scaffold( 28 | body: Padding( 29 | padding: const EdgeInsets.all(8.0), 30 | child: Center( 31 | child: ListView( 32 | shrinkWrap: true, 33 | children: [ 34 | Lottie.asset( 35 | 'assets/images/splash_screen_animation_lottie_json.json', 36 | width: width, 37 | height: width, 38 | fit: BoxFit.fill, 39 | controller: _animationController, onLoaded: (composition) { 40 | _animationController 41 | ..duration = composition.duration 42 | ..forward().whenComplete(() => Navigator.of(context) 43 | .pushAndRemoveUntil( 44 | MaterialPageRoute(builder: (context) { 45 | return BaseScreen(); 46 | }), (route) => false)); 47 | }), 48 | sized30, 49 | const Text( 50 | 'LAVENDER', 51 | style: logoTextStyle, 52 | textAlign: TextAlign.center, 53 | ) 54 | ], 55 | )), 56 | ), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/series/series_categories_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../../data/series/series_categories.dart'; 4 | import '../../../utils/constants.dart'; 5 | import '../../widgets/categories_widget.dart'; 6 | import 'series_list_page.dart'; 7 | 8 | class SeriesCategoriesPage extends StatefulWidget { 9 | const SeriesCategoriesPage({Key key}) : super(key: key); 10 | 11 | @override 12 | _SeriesCategoriesPageState createState() => _SeriesCategoriesPageState(); 13 | } 14 | 15 | class _SeriesCategoriesPageState extends State { 16 | var seriesCateroiesList = seriesCategories; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | } 22 | 23 | void onSearchBarValueChangeFunction(String searchText) { 24 | final searchedChannels = seriesCategories.where((category) { 25 | final categoryNameToLowerCase = category.categoryName.toLowerCase(); 26 | final searchTextToLowerCase = searchText.toLowerCase(); 27 | 28 | return categoryNameToLowerCase.contains(searchTextToLowerCase); 29 | }).toList(); 30 | 31 | setState(() { 32 | this.seriesCateroiesList = searchedChannels; 33 | }); 34 | } 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | return Scaffold( 39 | appBar: AppBar( 40 | centerTitle: true, 41 | title: const Text( 42 | 'Series Categories', 43 | style: logoTextStyle, 44 | ), 45 | ), 46 | body: CategoriesWidget( 47 | onSearchBarValueChangeFunction: onSearchBarValueChangeFunction, 48 | categoriesList: seriesCateroiesList, 49 | onTapNavigate: (categoryUrl, categoryName) { 50 | Navigator.of(context).push(MaterialPageRoute(builder: (context) { 51 | return SeriesListPage( 52 | categoryUrl: categoryUrl, categoryName: categoryName); 53 | })); 54 | }, 55 | )); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/movies/movies_categories_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lavender/presentation/pages/movies/movies_list_page.dart'; 3 | 4 | import '../../../data/movies/movies_categories.dart'; 5 | import '../../../utils/constants.dart'; 6 | import '../../widgets/categories_widget.dart'; 7 | 8 | class MoviesCategoriesPage extends StatefulWidget { 9 | const MoviesCategoriesPage({Key key}) : super(key: key); 10 | 11 | @override 12 | _MoviesCategoriesPageState createState() => _MoviesCategoriesPageState(); 13 | } 14 | 15 | class _MoviesCategoriesPageState extends State { 16 | var movieCateroiesList = movieCategories; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | } 22 | 23 | void onSearchBarValueChangeFunction(String searchText) { 24 | final searchedChannels = movieCategories.where((category) { 25 | final categoryNameToLowerCase = category.categoryName.toLowerCase(); 26 | final searchTextToLowerCase = searchText.toLowerCase(); 27 | 28 | return categoryNameToLowerCase.contains(searchTextToLowerCase); 29 | }).toList(); 30 | 31 | setState(() { 32 | this.movieCateroiesList = searchedChannels; 33 | }); 34 | } 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | return Scaffold( 39 | appBar: AppBar( 40 | centerTitle: true, 41 | title: const Text( 42 | 'Movies Categories', 43 | style: logoTextStyle, 44 | ), 45 | ), 46 | body: CategoriesWidget( 47 | onSearchBarValueChangeFunction: onSearchBarValueChangeFunction, 48 | categoriesList: movieCateroiesList, 49 | onTapNavigate: (categoryUrl, categoryName) { 50 | Navigator.of(context).push(MaterialPageRoute(builder: (context) { 51 | return MovieListPage( 52 | categoryUrl: categoryUrl, categoryName: categoryName); 53 | })); 54 | }, 55 | )); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lavender_app/lib/data/channels/channel.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | 5 | import 'language.dart'; 6 | 7 | class Channel { 8 | final String name; 9 | final String logo; 10 | final String url; 11 | final String category; 12 | 13 | 14 | const Channel({ 15 | @required this.name, 16 | @required this.logo, 17 | @required this.url, 18 | @required this.category, 19 | 20 | }); 21 | 22 | Channel copyWith({ 23 | String name, 24 | String logo, 25 | String url, 26 | String category, 27 | List languages, 28 | }) { 29 | return Channel( 30 | name: name ?? this.name, 31 | logo: logo ?? this.logo, 32 | url: url ?? this.url, 33 | category: category ?? this.category, 34 | 35 | ); 36 | } 37 | 38 | Map toMap() { 39 | return { 40 | 'name': name, 41 | 'logo': logo, 42 | 'url': url, 43 | 'category': category, 44 | 45 | }; 46 | } 47 | 48 | factory Channel.fromMap(Map map) { 49 | return Channel( 50 | name: map['name'] as String, 51 | logo: map['logo'] as String, 52 | url: map['url'] as String, 53 | category: map['category'] as String, 54 | 55 | ); 56 | } 57 | 58 | String toJson() => json.encode(toMap()); 59 | 60 | factory Channel.fromJson(String source) => 61 | Channel.fromMap(json.decode(source)); 62 | 63 | @override 64 | String toString() { 65 | return 'Channel(name: $name, logo: $logo, url: $url, category: $category)'; 66 | } 67 | 68 | @override 69 | bool operator ==(Object other) { 70 | if (identical(this, other)) return true; 71 | 72 | return other is Channel && 73 | other.name == name && 74 | other.logo == logo && 75 | other.url == url && 76 | other.category == category; 77 | } 78 | 79 | @override 80 | int get hashCode { 81 | return name.hashCode ^ 82 | logo.hashCode ^ 83 | url.hashCode ^ 84 | category.hashCode; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/bloc/home_page_bloc/homepage_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:bloc/bloc.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:flutter/foundation.dart'; 7 | 8 | import '../../../data/comming_soon/comming_soon.dart'; 9 | import '../../../data/movies/movies.dart'; 10 | import '../../../domain/repositories/network_repo.dart'; 11 | 12 | part 'homepage_event.dart'; 13 | part 'homepage_state.dart'; 14 | 15 | class HomePageBloc extends Bloc { 16 | static final networkRepo = NetworkRepo(); 17 | HomePageBloc() : super(HomePageLoadingState()); 18 | 19 | @override 20 | Stream mapEventToState( 21 | HomePageEvent event, 22 | ) async* { 23 | if (event is GetHomePageData) { 24 | yield HomePageLoadingState(); 25 | try { 26 | // print(DateTime.now().toString()); 27 | // final value = await Future.wait( 28 | // [networkRepo.trendingList(), networkRepo.getFeaturedBanner(),networkRepo.newArrivalList() , networkRepo.getCommingSoonList()]); 29 | 30 | // value.forEach((element) { 31 | // print(element.toString()); 32 | // element.forEach((subelement) { 33 | // print(subelement.toString()); 34 | // }); 35 | // }); 36 | // print(DateTime.now().toString()); 37 | final List trendingList = await networkRepo.trendingList(); 38 | final Movie featuredBanner = await networkRepo.getFeaturedBanner(); 39 | final List newArrivals = await networkRepo.newArrivalList(); 40 | final List commingSoonList = 41 | await networkRepo.getCommingSoonList(); 42 | // print(DateTime.now().toString()); 43 | yield HomePageLoadedState( 44 | trendingList: trendingList, 45 | featuredBanner: featuredBanner, 46 | newArrivals: newArrivals, 47 | commingSoonList: commingSoonList); 48 | } on IOException { 49 | yield HomePageNoInternetState(); 50 | } catch (e) { 51 | print(e.toString()); 52 | yield HomePageErrorState(); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/base_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import '../../utils/constants.dart'; 5 | import 'channels/channel_page.dart'; 6 | import 'home_page.dart'; 7 | import 'movies/movies_categories_page.dart'; 8 | import 'series/series_categories_page.dart'; 9 | 10 | class BaseScreen extends StatefulWidget { 11 | BaseScreen({Key key}) : super(key: key); 12 | 13 | @override 14 | _BaseScreenState createState() => _BaseScreenState(); 15 | } 16 | 17 | class _BaseScreenState extends State { 18 | var currentScreen = 0; 19 | 20 | static const _screenList = [ 21 | HomePage(), 22 | ChannelPage(), 23 | MoviesCategoriesPage(), 24 | SeriesCategoriesPage() 25 | ]; 26 | 27 | void changeScreen(int newScreenValue) { 28 | setState(() { 29 | currentScreen = newScreenValue; 30 | }); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Scaffold( 36 | body: Container(child: _screenList.elementAt(currentScreen)), 37 | bottomNavigationBar: BottomNavigationBar( 38 | type: BottomNavigationBarType.fixed, 39 | items: [ 40 | BottomNavigationBarItem( 41 | icon: Icon( 42 | CupertinoIcons.home, 43 | ), 44 | label: 'Home'), 45 | BottomNavigationBarItem( 46 | icon: Icon( 47 | CupertinoIcons.tv, 48 | ), 49 | label: 'Tv Channel'), 50 | BottomNavigationBarItem( 51 | icon: Icon( 52 | CupertinoIcons.film, 53 | ), 54 | label: 'Movies'), 55 | BottomNavigationBarItem( 56 | icon: Icon( 57 | CupertinoIcons.tickets, 58 | ), 59 | label: 'Series'), 60 | ], 61 | backgroundColor: darkGreyColor, 62 | currentIndex: currentScreen, 63 | onTap: changeScreen, 64 | selectedItemColor: darkBlueColor, 65 | selectedLabelStyle: TextStyle(color: whiteColor), 66 | unselectedItemColor: whiteColor, 67 | ), 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lavender_app/lib/data/movies/movies.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | 5 | class Movie { 6 | final String name; 7 | final String logo; 8 | final String url; 9 | final String language; 10 | final String description; 11 | const Movie({ 12 | @required this.name, 13 | @required this.logo, 14 | @required this.url, 15 | @required this.language, 16 | @required this.description, 17 | }); 18 | 19 | Movie copyWith({ 20 | String name, 21 | String logo, 22 | String url, 23 | String language, 24 | String description, 25 | }) { 26 | return Movie( 27 | name: name ?? this.name, 28 | logo: logo ?? this.logo, 29 | url: url ?? this.url, 30 | language: language ?? this.language, 31 | description: description ?? this.description, 32 | ); 33 | } 34 | 35 | Map toMap() { 36 | return { 37 | 'name': name, 38 | 'logo': logo, 39 | 'url': url, 40 | 'language': language, 41 | 'description': description, 42 | }; 43 | } 44 | 45 | factory Movie.fromMap(Map map) { 46 | return Movie( 47 | name: map['name'], 48 | logo: map['logo'], 49 | url: map['url'], 50 | language: map['language'], 51 | description: map['description'], 52 | ); 53 | } 54 | 55 | String toJson() => json.encode(toMap()); 56 | 57 | factory Movie.fromJson(String source) => Movie.fromMap(json.decode(source)); 58 | 59 | @override 60 | String toString() { 61 | return 'Movie(name: $name, logo: $logo, url: $url, language: $language, description: $description)'; 62 | } 63 | 64 | @override 65 | bool operator ==(Object other) { 66 | if (identical(this, other)) return true; 67 | 68 | return other is Movie && 69 | other.name == name && 70 | other.logo == logo && 71 | other.url == url && 72 | other.language == language && 73 | other.description == description; 74 | } 75 | 76 | @override 77 | int get hashCode { 78 | return name.hashCode ^ 79 | logo.hashCode ^ 80 | url.hashCode ^ 81 | language.hashCode ^ 82 | description.hashCode; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/view_media_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:lavender/utils/constants.dart'; 4 | import 'package:yoyo_player/yoyo_player.dart'; 5 | 6 | class ViewMediaPage extends StatefulWidget { 7 | final String source; 8 | const ViewMediaPage({Key key, @required this.source}) : super(key: key); 9 | 10 | @override 11 | _ViewMediaPageState createState() => _ViewMediaPageState(); 12 | } 13 | 14 | class _ViewMediaPageState extends State { 15 | 16 | 17 | 18 | 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | var aspectRatio = MediaQuery.of(context).orientation == Orientation.portrait ? 16/9 : 1.0 ; 23 | return Scaffold( 24 | body: widget.source.isNotEmpty 25 | ? Container( 26 | child: Center( 27 | child: YoYoPlayer( 28 | 29 | aspectRatio: aspectRatio, 30 | url: widget.source, 31 | videoStyle: VideoStyle( 32 | play: Icon(CupertinoIcons.play_circle), 33 | pause: Icon(CupertinoIcons.play_circle), 34 | ), 35 | videoLoadingStyle: VideoLoadingStyle( 36 | loading: Center( 37 | child: Column( 38 | children: const [ 39 | const CircularProgressIndicator( 40 | backgroundColor: whiteColor, 41 | ), 42 | const SizedBox( 43 | height: 10.0, 44 | ), 45 | const Text( 46 | "Loading video", 47 | style: TextStyle(color: whiteColor), 48 | ), 49 | ], 50 | )), 51 | ), 52 | ), 53 | ), 54 | ) 55 | : Center( 56 | child: Container( 57 | child: Text( 58 | 'Source down', 59 | style: TextStyle(color: whiteColor), 60 | ), 61 | ), 62 | ), 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lavender_app/lib/data/series/episode.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | 5 | class Episode { 6 | final String episodeName; 7 | final String episodeDescription; 8 | final String episodeUrl; 9 | final String episodeLogo; 10 | const Episode({ 11 | @required this.episodeName, 12 | @required this.episodeDescription, 13 | @required this.episodeUrl, 14 | @required this.episodeLogo, 15 | }); 16 | 17 | Episode copyWith({ 18 | String episodeName, 19 | String episodeDescription, 20 | String episodeUrl, 21 | String episodeLogo, 22 | }) { 23 | return Episode( 24 | episodeName: episodeName ?? this.episodeName, 25 | episodeDescription: episodeDescription ?? this.episodeDescription, 26 | episodeUrl: episodeUrl ?? this.episodeUrl, 27 | episodeLogo: episodeLogo ?? this.episodeLogo, 28 | ); 29 | } 30 | 31 | Map toMap() { 32 | return { 33 | 'episodeName': episodeName, 34 | 'episodeDescription': episodeDescription, 35 | 'episodeUrl': episodeUrl, 36 | 'episodeLogo': episodeLogo, 37 | }; 38 | } 39 | 40 | factory Episode.fromMap(Map map) { 41 | return Episode( 42 | episodeName: map['episodeName'], 43 | episodeDescription: map['episodeDescription'], 44 | episodeUrl: map['episodeUrl'], 45 | episodeLogo: map['episodeLogo'], 46 | ); 47 | } 48 | 49 | String toJson() => json.encode(toMap()); 50 | 51 | factory Episode.fromJson(String source) => Episode.fromMap(json.decode(source)); 52 | 53 | @override 54 | String toString() { 55 | return 'Episode(episodeName: $episodeName, episodeDescription: $episodeDescription, episodeUrl: $episodeUrl, episodeLogo: $episodeLogo)'; 56 | } 57 | 58 | @override 59 | bool operator ==(Object other) { 60 | if (identical(this, other)) return true; 61 | 62 | return other is Episode && 63 | other.episodeName == episodeName && 64 | other.episodeDescription == episodeDescription && 65 | other.episodeUrl == episodeUrl && 66 | other.episodeLogo == episodeLogo; 67 | } 68 | 69 | @override 70 | int get hashCode { 71 | return episodeName.hashCode ^ 72 | episodeDescription.hashCode ^ 73 | episodeUrl.hashCode ^ 74 | episodeLogo.hashCode; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lavender_app/lib/data/series/series.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | 5 | import 'seasons.dart'; 6 | 7 | class Series { 8 | final String name; 9 | final String logo; 10 | final List seasons; 11 | final String language; 12 | final String description; 13 | Series({ 14 | @required this.name, 15 | @required this.logo, 16 | @required this.seasons, 17 | @required this.language, 18 | @required this.description, 19 | }); 20 | 21 | Series copyWith({ 22 | String name, 23 | String logo, 24 | List seasons, 25 | String language, 26 | String description, 27 | }) { 28 | return Series( 29 | name: name ?? this.name, 30 | logo: logo ?? this.logo, 31 | seasons: seasons ?? this.seasons, 32 | language: language ?? this.language, 33 | description: description ?? this.description, 34 | ); 35 | } 36 | 37 | Map toMap() { 38 | return { 39 | 'name': name, 40 | 'logo': logo, 41 | 'seasons': seasons?.map((x) => x.toMap())?.toList(), 42 | 'language': language, 43 | 'description': description, 44 | }; 45 | } 46 | 47 | factory Series.fromMap(Map map) { 48 | return Series( 49 | name: map['name'], 50 | logo: map['logo'], 51 | seasons: List.from(map['seasons']?.map((x) => Seasons.fromMap(x))), 52 | language: map['language'], 53 | description: map['description'], 54 | ); 55 | } 56 | 57 | String toJson() => json.encode(toMap()); 58 | 59 | factory Series.fromJson(String source) => Series.fromMap(json.decode(source)); 60 | 61 | @override 62 | String toString() { 63 | return 'Series(name: $name, logo: $logo, seasons: $seasons, language: $language, description: $description)'; 64 | } 65 | 66 | @override 67 | bool operator ==(Object other) { 68 | if (identical(this, other)) return true; 69 | 70 | return other is Series && 71 | other.name == name && 72 | other.logo == logo && 73 | listEquals(other.seasons, seasons) && 74 | other.language == language && 75 | other.description == description; 76 | } 77 | 78 | @override 79 | int get hashCode { 80 | return name.hashCode ^ 81 | logo.hashCode ^ 82 | seasons.hashCode ^ 83 | language.hashCode ^ 84 | description.hashCode; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lavender_app/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 | 8 | 15 | 19 | 23 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /lavender_app/lib/data/series/seasons.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | 5 | import 'package:lavender/data/series/episode.dart'; 6 | 7 | class Seasons { 8 | final String seasonName; 9 | final String seasonDescription; 10 | final String seasonLogo; 11 | final List episodes; 12 | const Seasons({ 13 | @required this.seasonName, 14 | @required this.seasonDescription, 15 | @required this.seasonLogo, 16 | @required this.episodes, 17 | }); 18 | 19 | Seasons copyWith({ 20 | String seasonName, 21 | String seasonDescription, 22 | String seasonLogo, 23 | List episodes, 24 | }) { 25 | return Seasons( 26 | seasonName: seasonName ?? this.seasonName, 27 | seasonDescription: seasonDescription ?? this.seasonDescription, 28 | seasonLogo: seasonLogo ?? this.seasonLogo, 29 | episodes: episodes ?? this.episodes, 30 | ); 31 | } 32 | 33 | Map toMap() { 34 | return { 35 | 'seasonName': seasonName, 36 | 'seasonDescription': seasonDescription, 37 | 'seasonLogo': seasonLogo, 38 | 'episodes': episodes?.map((x) => x.toMap())?.toList(), 39 | }; 40 | } 41 | 42 | factory Seasons.fromMap(Map map) { 43 | return Seasons( 44 | seasonName: map['seasonName'], 45 | seasonDescription: map['seasonDescription'], 46 | seasonLogo: map['seasonLogo'], 47 | episodes: List.from(map['episodes']?.map((x) => Episode.fromMap(x))), 48 | ); 49 | } 50 | 51 | String toJson() => json.encode(toMap()); 52 | 53 | factory Seasons.fromJson(String source) => Seasons.fromMap(json.decode(source)); 54 | 55 | @override 56 | String toString() { 57 | return 'Seasons(seasonName: $seasonName, seasonDescription: $seasonDescription, seasonLogo: $seasonLogo, episodes: $episodes)'; 58 | } 59 | 60 | @override 61 | bool operator ==(Object other) { 62 | if (identical(this, other)) return true; 63 | 64 | return other is Seasons && 65 | other.seasonName == seasonName && 66 | other.seasonDescription == seasonDescription && 67 | other.seasonLogo == seasonLogo && 68 | listEquals(other.episodes, episodes); 69 | } 70 | 71 | @override 72 | int get hashCode { 73 | return seasonName.hashCode ^ 74 | seasonDescription.hashCode ^ 75 | seasonLogo.hashCode ^ 76 | episodes.hashCode; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/list_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../utils/constants.dart'; 4 | import 'Grid_Card.dart'; 5 | import 'search_bar.dart'; 6 | 7 | class ListScreen extends StatefulWidget { 8 | final List list; 9 | final Function(Object) navigationFunction; 10 | final searchHint; 11 | const ListScreen({ 12 | Key key, 13 | @required this.list, 14 | @required this.navigationFunction, 15 | @required this.searchHint 16 | }) : super(key: key); 17 | 18 | @override 19 | _ListScreenState createState() => _ListScreenState(); 20 | } 21 | 22 | class _ListScreenState extends State { 23 | List itemList = []; 24 | @override 25 | void initState() { 26 | super.initState(); 27 | itemList = widget.list; 28 | } 29 | 30 | void onSearchBarValueChangeFunction(String searchText) { 31 | final searched = widget.list.where((item) { 32 | final listItemNameToLowerCase = item.name.toLowerCase(); 33 | final searchTextToLowerCase = searchText.toLowerCase(); 34 | 35 | return listItemNameToLowerCase.contains(searchTextToLowerCase); 36 | }).toList(); 37 | 38 | setState(() { 39 | this.itemList = searched; 40 | }); 41 | } 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | return CustomScrollView(slivers: [ 46 | const SliverToBoxAdapter( 47 | child: SizedBox( 48 | height: 10.0, 49 | ), 50 | ), 51 | SliverToBoxAdapter( 52 | child: SearchBar( 53 | searchHint: widget.searchHint, 54 | onchangeFunction: onSearchBarValueChangeFunction)), 55 | const SliverToBoxAdapter( 56 | child: SizedBox( 57 | height: 10.0, 58 | ), 59 | ), 60 | SliverGrid( 61 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 62 | crossAxisCount: 2, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0), 63 | delegate: SliverChildBuilderDelegate( 64 | (context, index) { 65 | return GestureDetector( 66 | onTap: () => widget.navigationFunction(itemList[index]), 67 | child: GridCard( 68 | name: itemList[index].name, 69 | logoUrl: itemList[index].logo, 70 | ), 71 | ); 72 | }, 73 | childCount: itemList.length, 74 | ), 75 | ), 76 | ]); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/channels/channel_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | 4 | import '../../../utils/constants.dart'; 5 | import '../../bloc/channel_page_bloc/channelpage_bloc.dart'; 6 | import '../../widgets/channel_screen.dart'; 7 | import '../../widgets/error_widget.dart'; 8 | 9 | class ChannelPage extends StatefulWidget { 10 | const ChannelPage({Key key}) : super(key: key); 11 | 12 | @override 13 | _ChannelPageState createState() => _ChannelPageState(); 14 | } 15 | 16 | class _ChannelPageState extends State { 17 | static const titleGeneralError = 'Error occure'; 18 | static const titleNetworkError = 'No Internet Connection'; 19 | 20 | ChannelPageBloc _channelPageBloc; 21 | 22 | @override 23 | void didChangeDependencies() { 24 | super.didChangeDependencies(); 25 | _channelPageBloc = ChannelPageBloc()..add(GetChannelListData()); 26 | } 27 | 28 | @override 29 | void dispose() { 30 | _channelPageBloc.close(); 31 | super.dispose(); 32 | } 33 | 34 | void retryFunction() async { 35 | _channelPageBloc.add(GetChannelListData()); 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | final size = MediaQuery.of(context).size; 41 | return Scaffold( 42 | appBar: AppBar( 43 | title: const Text( 44 | 'Tv Channel', 45 | style: logoTextStyle, 46 | ), 47 | centerTitle: true, 48 | ), 49 | body: BlocConsumer( 50 | bloc: _channelPageBloc, 51 | listener: (context, state) {}, 52 | builder: (context, state) { 53 | if (state is ChannelPageLoadingState) { 54 | return const Center(child: const CircularProgressIndicator()); 55 | } else if (state is ChannelPageLoadedState) { 56 | return ChannelScreen(size: size, channelList: state.channelList); 57 | } else if (state is ChannelPageNoInternetState) { 58 | return CustomeErrorWidget( 59 | retryFunction: retryFunction, 60 | errorTitle: titleNetworkError, 61 | ); 62 | } else { 63 | return CustomeErrorWidget( 64 | retryFunction: retryFunction, 65 | errorTitle: titleGeneralError, 66 | ); 67 | } 68 | }, 69 | )); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lavender_serverCode/routers/horror_movies.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_horrorMoviesList = [ 5 | 6 | { 7 | "name":"Blue call(360p)", 8 | "logo":"https://m.media-amazon.com/images/M/MV5BZjk4NzlhMjYtMjhlZi00MjIzLWFkZjAtMzBhMWZhNjZhNDExXkEyXkFqcGdeQXVyMjIxODA2MTA@._V1_FMjpg_UY682_.jpg", 9 | "type":"m38u", 10 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 11 | "language":"English", 12 | "description":"Haylee, a local EMT suffering from PTSD, spends her days making split second decisions with lives that hang in the balance. One night on a routine call, she is faced with a moral decision, taking matters into her own hands and mercy kills a young woman. Her decision opens a pandora's box that leads Haylee to blur the lines of her job responsibilities and wanting to help those in need. Now, falling deeper and deeper into a rabbit hole, she gets caught up in a world of underground drugs and a sadistic killer who's made her his next victim." 13 | }, 14 | { 15 | "name":"Blue call(720p)", 16 | "logo":"https://m.media-amazon.com/images/M/MV5BZjk4NzlhMjYtMjhlZi00MjIzLWFkZjAtMzBhMWZhNjZhNDExXkEyXkFqcGdeQXVyMjIxODA2MTA@._V1_FMjpg_UY682_.jpg", 17 | "type":"m38u", 18 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 19 | "language":"English", 20 | "description":"Haylee, a local EMT suffering from PTSD, spends her days making split second decisions with lives that hang in the balance. One night on a routine call, she is faced with a moral decision, taking matters into her own hands and mercy kills a young woman. Her decision opens a pandora's box that leads Haylee to blur the lines of her job responsibilities and wanting to help those in need. Now, falling deeper and deeper into a rabbit hole, she gets caught up in a world of underground drugs and a sadistic killer who's made her his next victim." 21 | }, 22 | 23 | 24 | ] ; 25 | 26 | 27 | 28 | router.get('/', async (req,res) => { 29 | if(req.Auth){ 30 | try { 31 | res.status('200').send(resJson_horrorMoviesList); 32 | } catch (error) { 33 | res.status('500').send('Server error'); 34 | } 35 | 36 | } 37 | else{ 38 | res.status('400').send('Auth fail'); 39 | } 40 | 41 | 42 | }); 43 | 44 | 45 | module.exports = router; -------------------------------------------------------------------------------- /lavender_app/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 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/search_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import '../../utils/constants.dart'; 5 | 6 | class SearchBar extends StatefulWidget { 7 | final String searchHint; 8 | final Function onchangeFunction; 9 | const SearchBar({ 10 | Key key, 11 | @required this.searchHint, 12 | @required this.onchangeFunction, 13 | }) : super(key: key); 14 | 15 | @override 16 | _SearchBarState createState() => _SearchBarState(); 17 | } 18 | 19 | class _SearchBarState extends State { 20 | TextEditingController textEditingController; 21 | 22 | @override 23 | void initState() { 24 | super.initState(); 25 | textEditingController = TextEditingController(); 26 | } 27 | 28 | @override 29 | void dispose() { 30 | textEditingController.dispose(); 31 | super.dispose(); 32 | } 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return Container( 37 | width: double.infinity, 38 | height: 70.0, 39 | margin: const EdgeInsets.symmetric(horizontal: 10.0), 40 | decoration: BoxDecoration( 41 | color: Colors.white.withOpacity(.05), 42 | borderRadius: BorderRadius.circular(50.0), 43 | ), 44 | padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 25.0), 45 | child: TextField( 46 | enableSuggestions: true, 47 | controller: textEditingController, 48 | cursorColor: darkBlueColor, 49 | style: TextStyle(color: Colors.white.withOpacity(.8)), 50 | decoration: InputDecoration( 51 | focusColor: darkBlueColor, 52 | border: InputBorder.none, 53 | hintText: widget.searchHint, 54 | prefixIcon: InkWell( 55 | child: Icon(CupertinoIcons.search, color: darkBlueColor), 56 | onTap: () { 57 | FocusScope.of(context).unfocus(); 58 | }, 59 | ), 60 | suffixIcon: textEditingController.text.isNotEmpty 61 | ? InkWell( 62 | child: Icon( 63 | CupertinoIcons.clear, 64 | color: Colors.redAccent, 65 | ), 66 | onTap: () { 67 | textEditingController.clear(); 68 | widget.onchangeFunction(''); 69 | FocusScope.of(context).requestFocus(FocusNode()); 70 | }, 71 | ) 72 | : null), 73 | onChanged: widget.onchangeFunction, 74 | ), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/horizontal_items_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../utils/constants.dart'; 4 | import '../pages/view_media_page.dart'; 5 | 6 | class HorizontalItemsList extends StatelessWidget { 7 | final String listTitle; 8 | final List list; 9 | const HorizontalItemsList( 10 | {Key key, @required this.listTitle, @required this.list}) 11 | : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Padding( 16 | padding: const EdgeInsets.symmetric(horizontal: 5.0), 17 | child: Column( 18 | crossAxisAlignment: CrossAxisAlignment.start, 19 | children: [ 20 | Row( 21 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 22 | children: [ 23 | Container( 24 | child: Text( 25 | listTitle, 26 | style: listTitleStyle, 27 | ), 28 | ), 29 | Container( 30 | child: Text( 31 | '(${list.length})', 32 | style: listTitleStyle, 33 | ), 34 | ), 35 | ], 36 | ), 37 | Container( 38 | margin: const EdgeInsets.symmetric(vertical: 5.0), 39 | height: 170.0, 40 | padding: const EdgeInsets.symmetric(vertical: 10.0), 41 | child: ListView.builder( 42 | shrinkWrap: true, 43 | scrollDirection: Axis.horizontal, 44 | itemCount: list.length, 45 | itemBuilder: (context, index) { 46 | return GestureDetector( 47 | onTap: () { 48 | Navigator.push(context, 49 | MaterialPageRoute(builder: (context) { 50 | return ViewMediaPage(source: list[index].url); 51 | })); 52 | }, 53 | child: Container( 54 | margin: const EdgeInsets.symmetric(horizontal: 5.0), 55 | height: 150.0, 56 | width: 100.0, 57 | decoration: BoxDecoration( 58 | image: DecorationImage( 59 | image: NetworkImage(list[index].logo), 60 | fit: BoxFit.contain, 61 | ), 62 | borderRadius: 63 | BorderRadius.all(Radius.circular(10.0))), 64 | ), 65 | ); 66 | }), 67 | ) 68 | ], 69 | ), 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/channel_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../data/channels/channel.dart'; 4 | import '../../utils/constants.dart'; 5 | import '../pages/view_media_page.dart'; 6 | import 'channel_card.dart'; 7 | import 'search_bar.dart'; 8 | 9 | class ChannelScreen extends StatefulWidget { 10 | const ChannelScreen({ 11 | Key key, 12 | @required this.size, 13 | @required this.channelList, 14 | }) : super(key: key); 15 | 16 | final Size size; 17 | final List channelList; 18 | 19 | @override 20 | _ChannelScreenState createState() => _ChannelScreenState(); 21 | } 22 | 23 | class _ChannelScreenState extends State { 24 | List channels = []; 25 | 26 | @override 27 | void initState() { 28 | super.initState(); 29 | channels = widget.channelList; 30 | } 31 | 32 | void onSearchBarValueChangeFunction(String searchText) { 33 | final searchedChannels = widget.channelList.where((channel) { 34 | final channelNameToLowerCase = channel.name.toLowerCase(); 35 | final searchTextToLowerCase = searchText.toLowerCase(); 36 | 37 | return channelNameToLowerCase.contains(searchTextToLowerCase); 38 | }).toList(); 39 | 40 | setState(() { 41 | this.channels = searchedChannels; 42 | }); 43 | } 44 | 45 | @override 46 | Widget build(BuildContext context) { 47 | return SingleChildScrollView( 48 | child: Column( 49 | children: [ 50 | sized10, 51 | SearchBar( 52 | searchHint: searchChannels, 53 | onchangeFunction: onSearchBarValueChangeFunction, 54 | ), 55 | sized10, 56 | Padding( 57 | padding: const EdgeInsets.all(20.0), 58 | child: GridView.builder( 59 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( 60 | crossAxisCount: 2, 61 | crossAxisSpacing: 20.0, 62 | mainAxisSpacing: 20.0), 63 | physics: NeverScrollableScrollPhysics(), 64 | shrinkWrap: true, 65 | itemCount: channels.length, 66 | itemBuilder: (context, index) { 67 | return InkWell( 68 | onTap: () { 69 | Navigator.push(context, 70 | MaterialPageRoute(builder: (context) { 71 | return ViewMediaPage(source: channels[index].url); 72 | })); 73 | }, 74 | child: ChannelCard( 75 | channelName: channels[index].name, 76 | channelLogo: channels[index].logo, 77 | size: widget.size, 78 | )); 79 | }), 80 | ), 81 | ], 82 | ), 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lavender_app/README.md: -------------------------------------------------------------------------------- 1 | # LAVENDER 📺 2 | 3 | A fully-functional video streaming app like netflix made in **Flutter** using **Custom Nodejs backend**. 4 | 5 | # How To Run This Project 🏃‍♂️ 6 | 1. Clone the repository. 7 | 2. Do `flutter pub get`. 8 | 9 | 10 | # Features 🚀 11 | 1. User can watch live tv. 12 | 2. User can watch latest Movies and series. 13 | 3. Get to know about all the upcoming movies/series. 14 | 15 | # Built With 🛠 16 | - [Flutter](https://flutter.dev/) - UI toolkit for building beautiful, natively compiled applications for mobile, web, desktop, and embedded devices from a single codebase. 17 | - [http](https://pub.dev/packages/http) - A composable, Future-based library for making HTTP requests. 18 | - [Bloc](https://pub.dev/packages/bloc) - A predictable state management library that helps implement the BLoC (Business Logic Component) design pattern. 19 | - [equatable](https://pub.dev/packages/equatable) - A Dart package that helps to implement value based equality without needing to explicitly override == and hashCode. 20 | - [yoyo_player](https://pub.dev/packages/yoyo_player) - yoyo_player is a video player that allows you to select HLS video streaming by selecting the quality 21 | - [lottie](https://pub.dev/packages/lottie) - To implement lottie animation. 22 | 23 | # Package Structure 🗼 24 | 25 | lib # Root Package 26 | 27 | ├── data #data layer 28 | | ├── channels #channels 29 | | │ ├── channel #channel model 30 | | │ └── language #language model 31 | │ ├── comming_soon 32 | | | └── comming_soon #comming_soon model 33 | │ ├── movies 34 | | | ├── movies_categories #movies_categories model 35 | | | └── movies #movie model 36 | │ └── series 37 | | ├── episode #episode model 38 | | ├── seasons #season model 39 | | ├── series_categories #series_categories model 40 | | └── series #series model 41 | | 42 | ├── domain #connect data layer with ui layer 43 | | └── repositories #single source of truth 44 | | └── network_repo #handel api request 45 | | 46 | ├── presentation #ui layer 47 | | ├── bloc #state management 48 | | ├── pages #app screens 49 | | └── widgets #widgets 50 | | 51 | ├── utils #utility 52 | | └── constants #contain constants 53 | | 54 | └── main.dart #entry point 55 | 56 | # Architecture 🏹 57 | This app uses **Clean Architecture**. 58 | 59 | 60 | ![Clean Architecture](https://i0.wp.com/resocoder.com/wp-content/uploads/2019/08/Clean-Architecture-Flutter-Diagram.png?w=556&ssl=1). 61 | 62 | # Features Under Progress 🐌 63 | 1. Web support. 64 | 65 | # Platform Supported 💻📱 66 | 67 | - [x] Android 68 | - [x] IOS 69 | 70 | -------------------------------------------------------------------------------- /lavender_app/lib/data/movies/movies_categories.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | class MoviesCategories { 4 | final String categoryName; 5 | final String categoryUrl; 6 | final String categoryLogo; 7 | const MoviesCategories( 8 | {@required this.categoryUrl, 9 | @required this.categoryLogo, 10 | @required this.categoryName}); 11 | } 12 | 13 | const List movieCategories = const [ 14 | MoviesCategories( 15 | categoryName: 'Action', 16 | categoryUrl: 'actionMovies', 17 | categoryLogo: 18 | 'https://t3.gstatic.com/images?q=tbn:ANd9GcQzBPeJBL1nrbE44py9eA0PFWzRQjQlW4NwjIBKuOMjVi4ou8UR'), 19 | MoviesCategories( 20 | categoryName: 'Adventure', 21 | categoryUrl: 'adventureMovies', 22 | categoryLogo: 23 | 'https://t3.gstatic.com/images?q=tbn:ANd9GcQzBPeJBL1nrbE44py9eA0PFWzRQjQlW4NwjIBKuOMjVi4ou8UR'), 24 | MoviesCategories( 25 | categoryName: 'Animated', 26 | categoryUrl: 'animatedMovies', 27 | categoryLogo: 28 | 'https://t3.gstatic.com/images?q=tbn:ANd9GcQzBPeJBL1nrbE44py9eA0PFWzRQjQlW4NwjIBKuOMjVi4ou8UR'), 29 | MoviesCategories( 30 | categoryName: 'Comedies', 31 | categoryUrl: 'comediesMovies', 32 | categoryLogo: 33 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 34 | MoviesCategories( 35 | categoryName: 'Dramas', 36 | categoryUrl: 'dramasMovies', 37 | categoryLogo: 38 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 39 | MoviesCategories( 40 | categoryName: 'Horror', 41 | categoryUrl: 'horrorMovies', 42 | categoryLogo: 43 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 44 | MoviesCategories( 45 | categoryName: 'Musical', 46 | categoryUrl: 'musicalMovies', 47 | categoryLogo: 48 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 49 | MoviesCategories( 50 | categoryName: 'Other', 51 | categoryUrl: 'otherMovies', 52 | categoryLogo: 53 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 54 | MoviesCategories( 55 | categoryName: 'RealLife', 56 | categoryUrl: 'reallifeMovies', 57 | categoryLogo: 58 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 59 | MoviesCategories( 60 | categoryName: 'Romantic', 61 | categoryUrl: 'romanticMovies', 62 | categoryLogo: 63 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 64 | ]; 65 | -------------------------------------------------------------------------------- /lavender_app/lib/data/series/series_categories.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | 3 | class SeriesCategories { 4 | final String categoryName; 5 | final String categoryUrl; 6 | final String categoryLogo; 7 | const SeriesCategories( 8 | {@required this.categoryUrl, 9 | @required this.categoryLogo, 10 | @required this.categoryName}); 11 | } 12 | 13 | const List seriesCategories = const [ 14 | SeriesCategories( 15 | categoryName: 'Action', 16 | categoryUrl: 'actionSeries', 17 | categoryLogo: 18 | 'https://t3.gstatic.com/images?q=tbn:ANd9GcQzBPeJBL1nrbE44py9eA0PFWzRQjQlW4NwjIBKuOMjVi4ou8UR'), 19 | SeriesCategories( 20 | categoryName: 'Adventure', 21 | categoryUrl: 'adventureSeries', 22 | categoryLogo: 23 | 'https://t3.gstatic.com/images?q=tbn:ANd9GcQzBPeJBL1nrbE44py9eA0PFWzRQjQlW4NwjIBKuOMjVi4ou8UR'), 24 | SeriesCategories( 25 | categoryName: 'Animated', 26 | categoryUrl: 'animatedSeries', 27 | categoryLogo: 28 | 'https://t3.gstatic.com/images?q=tbn:ANd9GcQzBPeJBL1nrbE44py9eA0PFWzRQjQlW4NwjIBKuOMjVi4ou8UR'), 29 | SeriesCategories( 30 | categoryName: 'Comedies', 31 | categoryUrl: 'comediesSeries', 32 | categoryLogo: 33 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 34 | SeriesCategories( 35 | categoryName: 'Dramas', 36 | categoryUrl: 'dramasSeries', 37 | categoryLogo: 38 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 39 | SeriesCategories( 40 | categoryName: 'Horror', 41 | categoryUrl: 'horrorSeries', 42 | categoryLogo: 43 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 44 | SeriesCategories( 45 | categoryName: 'Musical', 46 | categoryUrl: 'musicalSeries', 47 | categoryLogo: 48 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 49 | SeriesCategories( 50 | categoryName: 'Other', 51 | categoryUrl: 'otherSeries', 52 | categoryLogo: 53 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 54 | SeriesCategories( 55 | categoryName: 'RealLife', 56 | categoryUrl: 'reallifeSeries', 57 | categoryLogo: 58 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 59 | SeriesCategories( 60 | categoryName: 'Romantic', 61 | categoryUrl: 'romanticSeries', 62 | categoryLogo: 63 | 'https://images.unsplash.com/photo-1509248961158-e54f6934749c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&q=80'), 64 | ]; 65 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/movies/movies_list_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | 4 | import '../../../utils/constants.dart'; 5 | import '../../bloc/movie_list_page_bloc/movielistpage_bloc.dart'; 6 | import '../../widgets/error_widget.dart'; 7 | import '../../widgets/list_screen.dart'; 8 | import 'movie_detail_page.dart'; 9 | 10 | class MovieListPage extends StatefulWidget { 11 | final String categoryUrl; 12 | final String categoryName; 13 | const MovieListPage({ 14 | Key key, 15 | @required this.categoryUrl, 16 | @required this.categoryName, 17 | }) : super(key: key); 18 | 19 | @override 20 | _MovieListPageState createState() => _MovieListPageState(); 21 | } 22 | 23 | class _MovieListPageState extends State { 24 | static const titleGeneralError = 'Error occure'; 25 | static const titleNetworkError = 'No Internet Connection'; 26 | static const searchHint = 'Enter Movie Name'; 27 | 28 | MovieListPageBloc _movieListPageBloc; 29 | 30 | @override 31 | void didChangeDependencies() { 32 | super.didChangeDependencies(); 33 | _movieListPageBloc = MovieListPageBloc() 34 | ..add(GetMovieListBaseOnCategory(categoryUrl: widget.categoryUrl)); 35 | } 36 | 37 | @override 38 | void dispose() { 39 | _movieListPageBloc.close(); 40 | super.dispose(); 41 | } 42 | 43 | void retryFunction() async { 44 | _movieListPageBloc 45 | .add(GetMovieListBaseOnCategory(categoryUrl: widget.categoryUrl)); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return Scaffold( 51 | appBar: AppBar( 52 | centerTitle: true, 53 | title: Text( 54 | widget.categoryName, 55 | style: logoTextStyle, 56 | ), 57 | ), 58 | body: BlocConsumer( 59 | bloc: _movieListPageBloc, 60 | listener: (context, state) {}, 61 | builder: (context, state) { 62 | if (state is MovieListPageLoadingState) { 63 | return const Center( 64 | child: const CircularProgressIndicator(), 65 | ); 66 | } else if (state is MovieListPageLoadedState) { 67 | return ListScreen( 68 | list: state.moviesList, 69 | searchHint: searchHint, 70 | navigationFunction: (movie) { 71 | return Navigator.push( 72 | context, 73 | MaterialPageRoute( 74 | builder: (context) { 75 | return MovieDetailPage( 76 | movie: movie, 77 | ); 78 | }, 79 | ), 80 | ); 81 | }, 82 | ); 83 | } else if (state is MovieListPageNoInternetState) { 84 | return CustomeErrorWidget( 85 | retryFunction: retryFunction, errorTitle: titleNetworkError); 86 | } else { 87 | return CustomeErrorWidget( 88 | retryFunction: retryFunction, 89 | errorTitle: titleGeneralError, 90 | ); 91 | } 92 | }, 93 | ), 94 | ); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/series/series_list_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:lavender/presentation/pages/series/series_detail_page.dart'; 4 | 5 | import '../../../utils/constants.dart'; 6 | import '../../bloc/series_list_page/serieslistpage_bloc.dart'; 7 | import '../../widgets/error_widget.dart'; 8 | import '../../widgets/list_screen.dart'; 9 | 10 | class SeriesListPage extends StatefulWidget { 11 | final String categoryUrl; 12 | final String categoryName; 13 | const SeriesListPage({ 14 | Key key, 15 | @required this.categoryUrl, 16 | @required this.categoryName, 17 | }) : super(key: key); 18 | 19 | @override 20 | _SeriesListPageState createState() => _SeriesListPageState(); 21 | } 22 | 23 | class _SeriesListPageState extends State { 24 | static const titleGeneralError = 'Error occure'; 25 | static const titleNetworkError = 'No Internet Connection'; 26 | static const searchHint = 'Enter Series Name'; 27 | 28 | SeriesListPageBloc _seriesListPageBloc; 29 | 30 | @override 31 | void didChangeDependencies() { 32 | super.didChangeDependencies(); 33 | _seriesListPageBloc = SeriesListPageBloc() 34 | ..add(GetSeriesListBaseOnCategory(categoryUrl: widget.categoryUrl)); 35 | } 36 | 37 | @override 38 | void dispose() { 39 | _seriesListPageBloc.close(); 40 | super.dispose(); 41 | } 42 | 43 | void retryFunction() async { 44 | _seriesListPageBloc 45 | .add(GetSeriesListBaseOnCategory(categoryUrl: widget.categoryUrl)); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return Scaffold( 51 | appBar: AppBar( 52 | centerTitle: true, 53 | title: Text( 54 | widget.categoryName, 55 | style: logoTextStyle, 56 | ), 57 | ), 58 | body: BlocConsumer( 59 | bloc: _seriesListPageBloc, 60 | listener: (context, state) {}, 61 | builder: (context, state) { 62 | if (state is SeriesListPageLoadingState) { 63 | return const Center( 64 | child: const CircularProgressIndicator(), 65 | ); 66 | } else if (state is SeriesListPageLoadedState) { 67 | return ListScreen( 68 | list: state.seriesList, 69 | searchHint: searchHint, 70 | navigationFunction: (series) { 71 | return Navigator.push( 72 | context, 73 | MaterialPageRoute( 74 | builder: (context) { 75 | return SeriesDetailPage( 76 | series: series, 77 | ); 78 | }, 79 | ), 80 | ); 81 | }, 82 | ); 83 | } else if (state is SeriesListPageNoInternetState) { 84 | return CustomeErrorWidget( 85 | retryFunction: retryFunction, errorTitle: titleNetworkError); 86 | } else { 87 | return CustomeErrorWidget( 88 | retryFunction: retryFunction, 89 | errorTitle: titleGeneralError, 90 | ); 91 | } 92 | }, 93 | ), 94 | ); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Banner](./github_assets/Lavender.png) 2 | # LAVENDER 📺 3 | 4 | A fully-functional video streaming app like netflix made in **Flutter** using **Custom Nodejs backend**. 5 | 6 | # How To Run This Project 🏃‍♂️ 7 | 1. Clone the repository. 8 | 2. cd lavendr_app 9 | 3. Do `flutter pub get`. 10 | 11 | 12 | # Features 🚀 13 | 1. User can watch live tv. 14 | 2. User can watch latest Movies and series. 15 | 3. Get to know about all the upcoming movies/series. 16 | 17 | # Built With 🛠 18 | - [Flutter](https://flutter.dev/) - UI toolkit for building beautiful, natively compiled applications for mobile, web, desktop, and embedded devices from a single codebase. 19 | - [http](https://pub.dev/packages/http) - A composable, Future-based library for making HTTP requests. 20 | - [Bloc](https://pub.dev/packages/bloc) - A predictable state management library that helps implement the BLoC (Business Logic Component) design pattern. 21 | - [equatable](https://pub.dev/packages/equatable) - A Dart package that helps to implement value based equality without needing to explicitly override == and hashCode. 22 | - [yoyo_player](https://pub.dev/packages/yoyo_player) - yoyo_player is a video player that allows you to select HLS video streaming by selecting the quality 23 | - [lottie](https://pub.dev/packages/lottie) - To implement lottie animation. 24 | - [nodeJS](https://nodejs.org/en/) - Node.js is a JavaScript runtime for server side code. 25 | - [express](https://expressjs.com/) - Fast, unopinionated, minimalist web framework for Node.js. 26 | 27 | # Package Structure for app 🗼 28 | 29 | lib # Root Package 30 | 31 | ├── data #data layer 32 | | ├── channels #channels 33 | | │ ├── channel #channel model 34 | | │ └── language #language model 35 | │ ├── comming_soon 36 | | | └── comming_soon #comming_soon model 37 | │ ├── movies 38 | | | ├── movies_categories #movies_categories model 39 | | | └── movies #movie model 40 | │ └── series 41 | | ├── episode #episode model 42 | | ├── seasons #season model 43 | | ├── series_categories #series_categories model 44 | | └── series #series model 45 | | 46 | ├── domain #connect data layer with ui layer 47 | | └── repositories #single source of truth 48 | | └── network_repo #handel api request 49 | | 50 | ├── presentation #ui layer 51 | | ├── bloc #state management 52 | | ├── pages #app screens 53 | | └── widgets #widgets 54 | | 55 | ├── utils #utility 56 | | └── constants #contain constants 57 | | 58 | └── main.dart #entry point 59 | 60 | # Architecture for app 🏹 61 | This app uses **Clean Architecture**. 62 | 63 | 64 | ![Clean Architecture](https://i0.wp.com/resocoder.com/wp-content/uploads/2019/08/Clean-Architecture-Flutter-Diagram.png?w=556&ssl=1). 65 | 66 | # Features Under Progress 🐌 67 | 1. Web support. 68 | 69 | # Platform Supported 💻📱 70 | 71 | - [x] Android 72 | - [x] IOS 73 | 74 | -------------------------------------------------------------------------------- /lavender_serverCode/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const cors = require('cors'); 3 | 4 | 5 | const app = express(); 6 | 7 | const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJIcml0aWsiLCJuYW1lIjoiWW91d2lsbG5ldmVyZ2V0aXQiLCJpYXQiOjE1MTYyMzkwMjJ9.6PRPWzmu_or76BASRLuP59ALvgWdQ8viGM9aThRojyY'; 8 | 9 | app.use(express.json()); 10 | app.use(cors()); 11 | 12 | 13 | //India channel list router 14 | const indianChannelList = require('./routers/indian_channel_list'); 15 | app.use('/indianChannelList',authorization ,indianChannelList); 16 | 17 | //animeList 18 | const animeList = require('./routers/anime_list'); 19 | app.use('/animeList',authorization ,animeList); 20 | 21 | 22 | //home page 23 | 24 | //Trending List 25 | const trendingList = require('./routers/trending'); 26 | app.use('/trendingList',authorization ,trendingList); 27 | 28 | //Trending List 29 | const newArrivalsList = require('./routers/new_arrivals'); 30 | app.use('/newarrivals',authorization ,newArrivalsList); 31 | 32 | //featuredbanner 33 | const featuredBanner = require('./routers/featuredBanner'); 34 | app.use('/featuredBanner',authorization ,featuredBanner); 35 | 36 | //comming_soon 37 | const comming_soon = require('./routers/comming_soon'); 38 | app.use('/commingsoon',authorization,comming_soon); 39 | 40 | 41 | 42 | //movie categories 43 | 44 | //animationMovieCategory 45 | const AnimatedMovies = require('./routers/Animated_movies'); 46 | app.use('/animatedMovies',authorization,AnimatedMovies); 47 | 48 | //horror movies category 49 | const horrorMovies = require('./routers/horror_movies'); 50 | app.use('/horrorMovies',authorization,horrorMovies); 51 | 52 | //action movies category 53 | const actionMovies = require('./routers/action_movie'); 54 | app.use('/actionMovies',authorization,actionMovies); 55 | 56 | 57 | //series 58 | 59 | //animated series 60 | const animatedSeries = require('./routers/animated_series'); 61 | app.use('/animatedSeries',authorization,animatedSeries); 62 | 63 | //horror series 64 | const horrorSeries = require('./routers/horror_series'); 65 | app.use('/horrorSeries',authorization,horrorSeries); 66 | 67 | //action series 68 | const actionSeries = require('./routers/action_series'); 69 | app.use('/actionSeries',authorization,actionSeries); 70 | 71 | 72 | //starting route 73 | app.get('/', authorization ,(req,res) => { 74 | if(req.Auth){ 75 | res.send("Server Connected"); 76 | }else{ 77 | res.send('Auth fail'); 78 | } 79 | 80 | }); 81 | 82 | 83 | 84 | //authorization 85 | function authorization(req,res,next){ 86 | 87 | const authHeader = req.headers['authorization']; 88 | const reqtoken = authHeader && authHeader.split(' ')[1]; 89 | if (reqtoken == null){ 90 | 91 | req.Auth = false; 92 | } 93 | if(reqtoken === token){ 94 | 95 | req.Auth = true; 96 | 97 | }else{ 98 | req.Auth = false; 99 | 100 | } 101 | next(); 102 | } 103 | 104 | 105 | 106 | const startServer = async () => { 107 | try { 108 | const PORT = process.env.PORT || 3000; 109 | app.listen(PORT, () => { 110 | console.log(`Server started `); 111 | }); 112 | } catch (error) { 113 | console.log(error); 114 | } 115 | } 116 | 117 | 118 | startServer(); 119 | 120 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/widgets/home_screen_banner.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import '../../utils/constants.dart'; 5 | import '../pages/view_media_page.dart'; 6 | 7 | class HomeScreenBanner extends StatelessWidget { 8 | static const String watch = 'Watch'; 9 | final Size size; 10 | final featuredBanner; 11 | const HomeScreenBanner({ 12 | Key key, 13 | @required this.size, 14 | @required this.featuredBanner, 15 | }) : super(key: key); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Container( 20 | height: size.height * 0.7, 21 | width: double.infinity, 22 | child: Stack( 23 | children: [ 24 | Container( 25 | height: size.height, 26 | width: double.infinity, 27 | decoration: BoxDecoration( 28 | image: DecorationImage( 29 | image: NetworkImage(featuredBanner.logo), 30 | fit: BoxFit.fill, 31 | )), 32 | ), 33 | Positioned( 34 | left: 0.0, 35 | top: size.height * 0.7, 36 | child: Container( 37 | width: size.width, 38 | child: Center( 39 | child: GestureDetector( 40 | onTap: () { 41 | Navigator.of(context) 42 | .push(MaterialPageRoute(builder: (context) { 43 | return ViewMediaPage(source: featuredBanner.url); 44 | })); 45 | }, 46 | child: Container( 47 | decoration: BoxDecoration( 48 | color: whiteColor, 49 | border: Border.all( 50 | color: Colors.black, 51 | style: BorderStyle.solid, 52 | ), 53 | borderRadius: BorderRadius.circular(20.0), 54 | boxShadow: [ 55 | BoxShadow( 56 | color: Colors.black.withOpacity(.7), 57 | blurRadius: 3.0, 58 | spreadRadius: 0.5) 59 | ]), 60 | child: Padding( 61 | padding: const EdgeInsets.all(8.0), 62 | child: Row( 63 | mainAxisSize: MainAxisSize.min, 64 | mainAxisAlignment: MainAxisAlignment.spaceAround, 65 | children: const [ 66 | const Padding( 67 | padding: const EdgeInsets.only(left: 10.0), 68 | child: const Icon( 69 | CupertinoIcons.play, 70 | color: Colors.black, 71 | ), 72 | ), 73 | const Padding( 74 | padding: const EdgeInsets.only(right: 10.0), 75 | child: const Text( 76 | watch, 77 | style: TextStyle(fontWeight: FontWeight.w700), 78 | ), 79 | ), 80 | ], 81 | ), 82 | ), 83 | ), 84 | ), 85 | ), 86 | )), 87 | ], 88 | ), 89 | ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lavender_app/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 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/series/season_detail_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import '../../../data/series/seasons.dart'; 5 | import '../../../utils/constants.dart'; 6 | import '../../widgets/series_season_display_card.dart'; 7 | import '../../widgets/widget_information_box.dart'; 8 | import 'episode_detail_page.dart'; 9 | 10 | class SeasonDetailPage extends StatefulWidget { 11 | final Seasons season; 12 | const SeasonDetailPage({ 13 | Key key, 14 | @required this.season, 15 | }) : super(key: key); 16 | 17 | @override 18 | _SeasonDetailPageState createState() => _SeasonDetailPageState(); 19 | } 20 | 21 | class _SeasonDetailPageState extends State { 22 | static const String description = 'Description: '; 23 | static const String episodes = 'Episodes'; 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | final double height = MediaQuery.of(context).size.height; 28 | final double width = MediaQuery.of(context).size.width; 29 | return Scaffold( 30 | body: SafeArea( 31 | child: SingleChildScrollView( 32 | child: Column( 33 | children: [ 34 | Container( 35 | width: width, 36 | height: height * 0.3, 37 | decoration: BoxDecoration( 38 | image: DecorationImage( 39 | image: NetworkImage(widget.season.seasonLogo), 40 | fit: BoxFit.cover, 41 | colorFilter: ColorFilter.mode( 42 | Colors.black.withOpacity(0.2), BlendMode.dstATop), 43 | ), 44 | ), 45 | child: Column( 46 | crossAxisAlignment: CrossAxisAlignment.start, 47 | children: [ 48 | GestureDetector( 49 | onTap: () => Navigator.of(context).pop(), 50 | child: Container( 51 | margin: const EdgeInsets.all(10.0), 52 | padding: const EdgeInsets.all(8.0), 53 | decoration: BoxDecoration( 54 | color: whiteColor, 55 | shape: BoxShape.circle, 56 | ), 57 | child: const Icon( 58 | CupertinoIcons.back, 59 | color: Colors.black, 60 | ), 61 | ), 62 | ), 63 | sized40, 64 | Column( 65 | children: [ 66 | Container( 67 | width: width, 68 | child: Center( 69 | child: Text( 70 | widget.season.seasonName, 71 | style: const TextStyle( 72 | color: Colors.white, 73 | fontWeight: FontWeight.w600, 74 | fontSize: 24.0), 75 | ), 76 | ), 77 | ), 78 | ], 79 | ), 80 | ], 81 | ), 82 | ), 83 | sized30, 84 | WidgetInformationBox( 85 | width: width, 86 | text: widget.season.seasonDescription, 87 | title: description, 88 | ), 89 | sized30, 90 | Center( 91 | child: const Text( 92 | episodes, 93 | style: commingSoonTitleStyle, 94 | ), 95 | ), 96 | ...widget.season.episodes.map((item) { 97 | return GestureDetector( 98 | onTap: () { 99 | Navigator.push(context, 100 | MaterialPageRoute(builder: (context) { 101 | return EpisodeDetailPage(episode: item); 102 | })); 103 | }, 104 | child: SeriesSeasonDisplayCard(episode: item), 105 | ); 106 | }).toList() 107 | ], 108 | ), 109 | ), 110 | ), 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/series/series_detail_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:lavender/presentation/pages/series/season_detail_page.dart'; 4 | 5 | import '../../../data/series/series.dart'; 6 | import '../../../utils/constants.dart'; 7 | import '../../widgets/series_season_display_card.dart'; 8 | import '../../widgets/widget_information_box.dart'; 9 | 10 | class SeriesDetailPage extends StatefulWidget { 11 | final Series series; 12 | const SeriesDetailPage({Key key, @required this.series}) : super(key: key); 13 | 14 | @override 15 | _SeriesDetailPageState createState() => _SeriesDetailPageState(); 16 | } 17 | 18 | class _SeriesDetailPageState extends State { 19 | static const String language = 'Language: '; 20 | static const String description = 'Description: '; 21 | static const String seasons = 'Seasons'; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | final double height = MediaQuery.of(context).size.height; 26 | final double width = MediaQuery.of(context).size.width; 27 | return Scaffold( 28 | body: SafeArea( 29 | child: SingleChildScrollView( 30 | child: Column( 31 | children: [ 32 | Container( 33 | width: width, 34 | height: height * 0.3, 35 | decoration: BoxDecoration( 36 | image: DecorationImage( 37 | image: NetworkImage(widget.series.logo), 38 | fit: BoxFit.cover, 39 | colorFilter: ColorFilter.mode( 40 | Colors.black.withOpacity(0.2), BlendMode.dstATop), 41 | ), 42 | ), 43 | child: Column( 44 | crossAxisAlignment: CrossAxisAlignment.start, 45 | children: [ 46 | GestureDetector( 47 | onTap: () => Navigator.of(context).pop(), 48 | child: Container( 49 | margin: const EdgeInsets.all(10.0), 50 | padding: const EdgeInsets.all(8.0), 51 | decoration: BoxDecoration( 52 | color: whiteColor, 53 | shape: BoxShape.circle, 54 | ), 55 | child: const Icon( 56 | CupertinoIcons.back, 57 | color: Colors.black, 58 | ), 59 | ), 60 | ), 61 | sized40, 62 | Column( 63 | children: [ 64 | Container( 65 | width: width, 66 | child: Center( 67 | child: Text( 68 | widget.series.name, 69 | style: const TextStyle( 70 | color: Colors.white, 71 | fontWeight: FontWeight.w600, 72 | fontSize: 24.0), 73 | ), 74 | ), 75 | ), 76 | ], 77 | ), 78 | ], 79 | ), 80 | ), 81 | sized30, 82 | WidgetInformationBox( 83 | width: width, 84 | text: widget.series.language, 85 | title: language, 86 | ), 87 | sized10, 88 | WidgetInformationBox( 89 | width: width, 90 | text: widget.series.description, 91 | title: description, 92 | ), 93 | sized30, 94 | Center( 95 | child: const Text( 96 | seasons, 97 | style: commingSoonTitleStyle, 98 | ), 99 | ), 100 | ...widget.series.seasons.map((item) { 101 | return GestureDetector( 102 | onTap: () { 103 | Navigator.push(context, 104 | MaterialPageRoute(builder: (context) { 105 | return SeasonDetailPage(season: item); 106 | })); 107 | }, 108 | child: SeriesSeasonDisplayCard( 109 | seasons: item, 110 | ), 111 | ); 112 | }).toList() 113 | ], 114 | ), 115 | ), 116 | ), 117 | ); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /lavender_app/lib/domain/repositories/network_repo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:http/http.dart' as http; 4 | 5 | import '../../data/channels/channel.dart'; 6 | import '../../data/comming_soon/comming_soon.dart'; 7 | import '../../data/movies/movies.dart'; 8 | import '../../data/series/series.dart'; 9 | import '../../utils/network_constants.dart'; 10 | 11 | class NetworkRepo { 12 | static final client = http.Client(); 13 | static const Map tokenData = { 14 | "Content-type": "application/x-www-form-urlencoded", 15 | "Authorization": NetworkConstants.token 16 | }; 17 | 18 | /// This is for channel section 19 | 20 | //get indian channel list 21 | Future> indianChannelList() async { 22 | List channelList = []; 23 | try { 24 | final response = await client.get( 25 | Uri.parse('${NetworkConstants.baseUrl}indianChannelList'), 26 | headers: tokenData); 27 | List parsed = jsonDecode(response.body).cast>(); 28 | 29 | parsed.forEach((_mapElement) { 30 | channelList.add(Channel.fromMap(_mapElement)); 31 | }); 32 | 33 | return channelList; 34 | } catch (e) { 35 | print(e.toString()); 36 | throw (e); 37 | } 38 | } 39 | 40 | ///this is for home page section 41 | 42 | //get featured banner 43 | Future getFeaturedBanner() async { 44 | try { 45 | final response = await client.get( 46 | Uri.parse('${NetworkConstants.baseUrl}featuredBanner'), 47 | headers: tokenData); 48 | 49 | final movie = Movie.fromJson(response.body); 50 | 51 | return movie; 52 | } catch (e) { 53 | throw (e); 54 | } 55 | } 56 | 57 | //get trending list 58 | Future> trendingList() async { 59 | List trendingList = []; 60 | try { 61 | final response = await client.get( 62 | Uri.parse('${NetworkConstants.baseUrl}trendingList'), 63 | headers: tokenData); 64 | List parsed = jsonDecode(response.body).cast>(); 65 | 66 | parsed.forEach((_mapElement) { 67 | trendingList.add(Movie.fromMap(_mapElement)); 68 | }); 69 | 70 | return trendingList; 71 | } catch (e) { 72 | throw (e); 73 | } 74 | } 75 | 76 | //new arrivals list 77 | Future> newArrivalList() async { 78 | List newArrivals = []; 79 | try { 80 | final response = await client.get( 81 | Uri.parse('${NetworkConstants.baseUrl}newarrivals'), 82 | headers: tokenData); 83 | List parsed = jsonDecode(response.body).cast>(); 84 | 85 | parsed.forEach((_mapElement) { 86 | newArrivals.add(Movie.fromMap(_mapElement)); 87 | }); 88 | 89 | return newArrivals; 90 | } catch (e) { 91 | throw (e); 92 | } 93 | } 94 | 95 | //comming_soon 96 | Future> getCommingSoonList() async { 97 | List commingsoonList = []; 98 | 99 | try { 100 | final response = await client.get( 101 | Uri.parse('${NetworkConstants.baseUrl}commingsoon'), 102 | headers: tokenData); 103 | List parsed = jsonDecode(response.body).cast>(); 104 | 105 | parsed.forEach((commingsoonElement) { 106 | commingsoonList.add(CommingSoon.fromMap(commingsoonElement)); 107 | }); 108 | 109 | return commingsoonList; 110 | } catch (e) { 111 | print(e.toString()); 112 | throw (e); 113 | } 114 | } 115 | 116 | /// movie page 117 | 118 | //get movie list according to category 119 | Future> getMovieCategoryList(String categoryUrl) async { 120 | List movieList = []; 121 | try { 122 | final response = await client.get( 123 | Uri.parse('${NetworkConstants.baseUrl}$categoryUrl'), 124 | headers: tokenData); 125 | List parsed = jsonDecode(response.body).cast>(); 126 | 127 | parsed.forEach((_mapElement) { 128 | movieList.add(Movie.fromMap(_mapElement)); 129 | }); 130 | return movieList; 131 | } catch (e) { 132 | throw (e); 133 | } 134 | } 135 | 136 | ///series page 137 | 138 | //get series list according to category 139 | Future> getSeriesCategoryList(String categoryUrl) async { 140 | List seriesList = []; 141 | try { 142 | final response = await client.get( 143 | Uri.parse('${NetworkConstants.baseUrl}$categoryUrl'), 144 | headers: tokenData); 145 | List parsed = jsonDecode(response.body).cast>(); 146 | 147 | parsed.forEach((_mapElement) { 148 | seriesList.add(Series.fromMap(_mapElement)); 149 | }); 150 | return seriesList; 151 | } catch (e) { 152 | throw (e); 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import '../../data/comming_soon/comming_soon.dart'; 4 | import '../widgets/comming_soon_banner.dart'; 5 | 6 | import '../../utils/constants.dart'; 7 | import '../bloc/home_page_bloc/homepage_bloc.dart'; 8 | import '../widgets/error_widget.dart'; 9 | import '../widgets/home_screen_banner.dart'; 10 | import '../widgets/horizontal_items_list.dart'; 11 | 12 | class HomePage extends StatefulWidget { 13 | const HomePage({Key key}) : super(key: key); 14 | 15 | @override 16 | _HomePageState createState() => _HomePageState(); 17 | } 18 | 19 | class _HomePageState extends State { 20 | static const titleGeneralError = 'Error occure'; 21 | static const titleNetworkError = 'No Internet Connection'; 22 | 23 | HomePageBloc _homePageBloc = HomePageBloc(); 24 | 25 | @override 26 | void didChangeDependencies() { 27 | super.didChangeDependencies(); 28 | _homePageBloc.add(GetHomePageData()); 29 | } 30 | 31 | @override 32 | void dispose() { 33 | _homePageBloc.close(); 34 | super.dispose(); 35 | } 36 | 37 | void retryFunction() async { 38 | _homePageBloc.add(GetHomePageData()); 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | return Scaffold( 44 | body: BlocBuilder( 45 | bloc: _homePageBloc, 46 | builder: (context, state) { 47 | if (state is HomePageLoadingState) { 48 | return const Center( 49 | child: CircularProgressIndicator(), 50 | ); 51 | } else if (state is HomePageLoadedState) { 52 | return WidgetHomePageLoadedState( 53 | newArrive: state.newArrivals, 54 | trendingList: state.trendingList, 55 | featuredBanner: state.featuredBanner, 56 | commingSoonList: state.commingSoonList, 57 | ); 58 | } else if (state is HomePageNoInternetState) { 59 | return CustomeErrorWidget( 60 | retryFunction: retryFunction, 61 | errorTitle: titleNetworkError, 62 | ); 63 | } else { 64 | return CustomeErrorWidget( 65 | retryFunction: retryFunction, 66 | errorTitle: titleGeneralError, 67 | ); 68 | } 69 | }, 70 | ), 71 | ); 72 | } 73 | } 74 | 75 | class WidgetHomePageLoadedState extends StatelessWidget { 76 | static const String titleNewArrive = 'New Arrive'; 77 | static const String titleTrending = 'Trending'; 78 | static const String appTitle = 'LAVENDER'; 79 | 80 | const WidgetHomePageLoadedState({ 81 | Key key, 82 | @required this.newArrive, 83 | @required this.trendingList, 84 | @required this.featuredBanner, 85 | @required this.commingSoonList, 86 | }) : super(key: key); 87 | 88 | final List newArrive; 89 | final List trendingList; 90 | final featuredBanner; 91 | final List commingSoonList; 92 | 93 | @override 94 | Widget build(BuildContext context) { 95 | final Size size = MediaQuery.of(context).size; 96 | return SafeArea( 97 | child: NestedScrollView( 98 | physics: NeverScrollableScrollPhysics(), 99 | headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { 100 | return [ 101 | SliverAppBar( 102 | pinned: true, 103 | floating: true, 104 | centerTitle: true, 105 | expandedHeight: size.height * 0.8, 106 | title: const Text( 107 | appTitle, 108 | style: logoTextStyle, 109 | ), 110 | flexibleSpace: FlexibleSpaceBar( 111 | centerTitle: true, 112 | background: HomeScreenBanner( 113 | size: size, 114 | featuredBanner: featuredBanner, 115 | ), 116 | ), 117 | ), 118 | ]; 119 | }, 120 | body: ListView( 121 | shrinkWrap: true, 122 | children: [ 123 | sized10, 124 | HorizontalItemsList(listTitle: titleTrending, list: trendingList), 125 | sized10, 126 | HorizontalItemsList(listTitle: titleNewArrive, list: newArrive), 127 | sized10, 128 | Container( 129 | child: Center( 130 | child: const Text( 131 | 'Comming Soon', 132 | style: commingSoonTitleStyle, 133 | ))), 134 | sized20, 135 | CommingSoonBanner(size: size, commingSoonList: commingSoonList), 136 | sized20 137 | ], 138 | )), 139 | ); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /lavender_serverCode/routers/trending.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_trendingList = [ 5 | { 6 | "name":"Godzilla vs Kong(Hindi audio)", 7 | "logo":"https://images-na.ssl-images-amazon.com/images/I/81SAqNnNlfL._AC_SL1500_.jpg", 8 | "type":"m38u", 9 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 10 | "language":"Hindi", 11 | "description":"Godzilla vs. Kong is a 2021 American monster film directed by Adam Wingard. A sequel to Godzilla: King of the Monsters (2019) and Kong: Skull Island (2017), it is the fourth film in Legendary's MonsterVerse. It is also the 36th film in the Godzilla franchise, the 12th film in the King Kong franchise, and the fourth Godzilla film to be completely produced by a Hollywood studio. The film stars Alexander Skarsgård, Millie Bobby Brown, Rebecca Hall, Brian Tyree Henry, Shun Oguri, Eiza González, Julian Dennison, Lance Reddick, Kyle Chandler, and Demián Bichir. In the film, Kong clashes with Godzilla as humans lure the ape into the Hollow Earth to retrieve a power source for a weapon to stop Godzilla's mysterious rampages." 12 | }, 13 | 14 | { 15 | "name":"Blue call(720p)", 16 | "logo":"https://m.media-amazon.com/images/M/MV5BZjk4NzlhMjYtMjhlZi00MjIzLWFkZjAtMzBhMWZhNjZhNDExXkEyXkFqcGdeQXVyMjIxODA2MTA@._V1_FMjpg_UY682_.jpg", 17 | "type":"m38u", 18 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 19 | "language":"English", 20 | "description":"Haylee, a local EMT suffering from PTSD, spends her days making split second decisions with lives that hang in the balance. One night on a routine call, she is faced with a moral decision, taking matters into her own hands and mercy kills a young woman. Her decision opens a pandora's box that leads Haylee to blur the lines of her job responsibilities and wanting to help those in need. Now, falling deeper and deeper into a rabbit hole, she gets caught up in a world of underground drugs and a sadistic killer who's made her his next victim." 21 | }, 22 | { 23 | "name":"Panda Vs Aliens(720p)", 24 | "logo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg", 25 | "type":"m38u", 26 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 27 | "language":"English", 28 | "description":"A group of aliens seek out to conquer new worlds and take particular notice of Earth, after seeing satellite broadcasts of TV shows of a powerful panda, Pandy." 29 | }, 30 | 31 | { 32 | "name":"Blue call(360p)", 33 | "logo":"https://m.media-amazon.com/images/M/MV5BZjk4NzlhMjYtMjhlZi00MjIzLWFkZjAtMzBhMWZhNjZhNDExXkEyXkFqcGdeQXVyMjIxODA2MTA@._V1_FMjpg_UY682_.jpg", 34 | "type":"m38u", 35 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 36 | "language":"English", 37 | "description":"Haylee, a local EMT suffering from PTSD, spends her days making split second decisions with lives that hang in the balance. One night on a routine call, she is faced with a moral decision, taking matters into her own hands and mercy kills a young woman. Her decision opens a pandora's box that leads Haylee to blur the lines of her job responsibilities and wanting to help those in need. Now, falling deeper and deeper into a rabbit hole, she gets caught up in a world of underground drugs and a sadistic killer who's made her his next victim." 38 | }, 39 | { 40 | "name":"Godzilla vs Kong(Hindi audio)", 41 | "logo":"https://images-na.ssl-images-amazon.com/images/I/81SAqNnNlfL._AC_SL1500_.jpg", 42 | "type":"m38u", 43 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 44 | "language":"Hindi", 45 | "description":"Godzilla vs. Kong is a 2021 American monster film directed by Adam Wingard. A sequel to Godzilla: King of the Monsters (2019) and Kong: Skull Island (2017), it is the fourth film in Legendary's MonsterVerse. It is also the 36th film in the Godzilla franchise, the 12th film in the King Kong franchise, and the fourth Godzilla film to be completely produced by a Hollywood studio. The film stars Alexander Skarsgård, Millie Bobby Brown, Rebecca Hall, Brian Tyree Henry, Shun Oguri, Eiza González, Julian Dennison, Lance Reddick, Kyle Chandler, and Demián Bichir. In the film, Kong clashes with Godzilla as humans lure the ape into the Hollow Earth to retrieve a power source for a weapon to stop Godzilla's mysterious rampages." 46 | }, 47 | ] ; 48 | 49 | 50 | 51 | router.get('/', async (req,res) => { 52 | if(req.Auth){ 53 | try { 54 | res.status('200').send(resJson_trendingList); 55 | } catch (error) { 56 | res.status('500').send('Server error'); 57 | } 58 | 59 | } 60 | else{ 61 | res.status('400').send('Auth fail'); 62 | } 63 | 64 | 65 | }); 66 | 67 | 68 | module.exports = router; -------------------------------------------------------------------------------- /lavender_serverCode/routers/new_arrivals.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_newArrivalsList = [ 5 | { 6 | "name":"Godzilla vs Kong(Hindi audio)", 7 | "logo":"https://images-na.ssl-images-amazon.com/images/I/81SAqNnNlfL._AC_SL1500_.jpg", 8 | "type":"m38u", 9 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 10 | "language":"Hindi", 11 | "description":"Godzilla vs. Kong is a 2021 American monster film directed by Adam Wingard. A sequel to Godzilla: King of the Monsters (2019) and Kong: Skull Island (2017), it is the fourth film in Legendary's MonsterVerse. It is also the 36th film in the Godzilla franchise, the 12th film in the King Kong franchise, and the fourth Godzilla film to be completely produced by a Hollywood studio. The film stars Alexander Skarsgård, Millie Bobby Brown, Rebecca Hall, Brian Tyree Henry, Shun Oguri, Eiza González, Julian Dennison, Lance Reddick, Kyle Chandler, and Demián Bichir. In the film, Kong clashes with Godzilla as humans lure the ape into the Hollow Earth to retrieve a power source for a weapon to stop Godzilla's mysterious rampages." 12 | }, 13 | 14 | { 15 | "name":"Blue call(720p)", 16 | "logo":"https://m.media-amazon.com/images/M/MV5BZjk4NzlhMjYtMjhlZi00MjIzLWFkZjAtMzBhMWZhNjZhNDExXkEyXkFqcGdeQXVyMjIxODA2MTA@._V1_FMjpg_UY682_.jpg", 17 | "type":"m38u", 18 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 19 | "language":"English", 20 | "description":"Haylee, a local EMT suffering from PTSD, spends her days making split second decisions with lives that hang in the balance. One night on a routine call, she is faced with a moral decision, taking matters into her own hands and mercy kills a young woman. Her decision opens a pandora's box that leads Haylee to blur the lines of her job responsibilities and wanting to help those in need. Now, falling deeper and deeper into a rabbit hole, she gets caught up in a world of underground drugs and a sadistic killer who's made her his next victim." 21 | }, 22 | { 23 | "name":"Panda Vs Aliens(720p)", 24 | "logo":"https://upload.wikimedia.org/wikipedia/en/a/ac/PandavsAliens.jpg", 25 | "type":"m38u", 26 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 27 | "language":"English", 28 | "description":"A group of aliens seek out to conquer new worlds and take particular notice of Earth, after seeing satellite broadcasts of TV shows of a powerful panda, Pandy." 29 | }, 30 | 31 | { 32 | "name":"Blue call(360p)", 33 | "logo":"https://m.media-amazon.com/images/M/MV5BZjk4NzlhMjYtMjhlZi00MjIzLWFkZjAtMzBhMWZhNjZhNDExXkEyXkFqcGdeQXVyMjIxODA2MTA@._V1_FMjpg_UY682_.jpg", 34 | "type":"m38u", 35 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 36 | "language":"English", 37 | "description":"Haylee, a local EMT suffering from PTSD, spends her days making split second decisions with lives that hang in the balance. One night on a routine call, she is faced with a moral decision, taking matters into her own hands and mercy kills a young woman. Her decision opens a pandora's box that leads Haylee to blur the lines of her job responsibilities and wanting to help those in need. Now, falling deeper and deeper into a rabbit hole, she gets caught up in a world of underground drugs and a sadistic killer who's made her his next victim." 38 | }, 39 | { 40 | "name":"Godzilla vs Kong(Hindi audio)", 41 | "logo":"https://images-na.ssl-images-amazon.com/images/I/81SAqNnNlfL._AC_SL1500_.jpg", 42 | "type":"m38u", 43 | "url":"https://llvod.mxplay.com/video/4fffa9037b466b90e5cf0022f0fb7ebc/6/hls/h264_baseline.m3u8", 44 | "language":"Hindi", 45 | "description":"Godzilla vs. Kong is a 2021 American monster film directed by Adam Wingard. A sequel to Godzilla: King of the Monsters (2019) and Kong: Skull Island (2017), it is the fourth film in Legendary's MonsterVerse. It is also the 36th film in the Godzilla franchise, the 12th film in the King Kong franchise, and the fourth Godzilla film to be completely produced by a Hollywood studio. The film stars Alexander Skarsgård, Millie Bobby Brown, Rebecca Hall, Brian Tyree Henry, Shun Oguri, Eiza González, Julian Dennison, Lance Reddick, Kyle Chandler, and Demián Bichir. In the film, Kong clashes with Godzilla as humans lure the ape into the Hollow Earth to retrieve a power source for a weapon to stop Godzilla's mysterious rampages." 46 | }, 47 | ] ; 48 | 49 | 50 | 51 | router.get('/', async (req,res) => { 52 | if(req.Auth){ 53 | try { 54 | res.status('200').send(resJson_newArrivalsList); 55 | } catch (error) { 56 | res.status('500').send('Server error'); 57 | } 58 | 59 | } 60 | else{ 61 | res.status('400').send('Auth fail'); 62 | } 63 | 64 | 65 | }); 66 | 67 | 68 | module.exports = router; -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/series/episode_detail_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import '../../../data/series/episode.dart'; 5 | import '../../../utils/constants.dart'; 6 | import '../../widgets/widget_information_box.dart'; 7 | import '../view_media_page.dart'; 8 | 9 | class EpisodeDetailPage extends StatefulWidget { 10 | final Episode episode; 11 | const EpisodeDetailPage({Key key, @required this.episode}) : super(key: key); 12 | 13 | @override 14 | _EpisodeDetailPageState createState() => _EpisodeDetailPageState(); 15 | } 16 | 17 | class _EpisodeDetailPageState extends State { 18 | static const String language = 'Language: '; 19 | static const String play = 'Play'; 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | final double height = MediaQuery.of(context).size.height; 24 | final double width = MediaQuery.of(context).size.width; 25 | return Scaffold( 26 | body: SafeArea( 27 | child: SingleChildScrollView( 28 | child: Column( 29 | children: [ 30 | Container( 31 | width: width, 32 | height: height * 0.4, 33 | decoration: BoxDecoration( 34 | image: DecorationImage( 35 | image: NetworkImage(widget.episode.episodeLogo), 36 | fit: BoxFit.cover, 37 | colorFilter: ColorFilter.mode( 38 | Colors.black.withOpacity(0.2), BlendMode.dstATop), 39 | ), 40 | ), 41 | child: Column( 42 | crossAxisAlignment: CrossAxisAlignment.start, 43 | children: [ 44 | GestureDetector( 45 | onTap: () => Navigator.of(context).pop(), 46 | child: Container( 47 | margin: const EdgeInsets.all(10.0), 48 | padding: const EdgeInsets.all(8.0), 49 | decoration: BoxDecoration( 50 | color: whiteColor, 51 | shape: BoxShape.circle, 52 | ), 53 | child: const Icon( 54 | CupertinoIcons.back, 55 | color: Colors.black, 56 | ), 57 | ), 58 | ), 59 | sized50, 60 | Column( 61 | children: [ 62 | Container( 63 | width: width, 64 | child: Center( 65 | child: Text( 66 | widget.episode.episodeName, 67 | style: const TextStyle( 68 | color: Colors.white, 69 | fontWeight: FontWeight.w600, 70 | fontSize: 24.0), 71 | ), 72 | ), 73 | ), 74 | ], 75 | ), 76 | height < 680 ? sized40 : sized50, 77 | Container( 78 | width: width, 79 | child: Center( 80 | child: GestureDetector( 81 | onTap: () { 82 | Navigator.of(context) 83 | .push(MaterialPageRoute(builder: (context) { 84 | return ViewMediaPage( 85 | source: widget.episode.episodeUrl); 86 | })); 87 | }, 88 | child: Container( 89 | width: width * 0.5, 90 | height: height * 0.05, 91 | decoration: BoxDecoration( 92 | borderRadius: BorderRadius.circular(20.0), 93 | color: Colors.redAccent), 94 | child: Center( 95 | child: Row( 96 | mainAxisSize: MainAxisSize.min, 97 | mainAxisAlignment: MainAxisAlignment.center, 98 | crossAxisAlignment: CrossAxisAlignment.center, 99 | children: const [ 100 | sized50, 101 | const Icon(CupertinoIcons.play), 102 | sized50, 103 | const Text( 104 | play, 105 | ), 106 | sized50 107 | ], 108 | ), 109 | ), 110 | ), 111 | ), 112 | ), 113 | ), 114 | ], 115 | ), 116 | ), 117 | sized30, 118 | WidgetInformationBox( 119 | width: width, 120 | text: widget.episode.episodeDescription, 121 | title: language, 122 | ), 123 | ], 124 | ), 125 | ), 126 | ), 127 | ); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lavender_serverCode/routers/indian_channel_list.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const resJson_IndianChannelList = [ 5 | { 6 | "name": "&Flix", 7 | "logo": "https://static.epg.best/in/AndFlix.in.png", 8 | "type":"m38u", 9 | "url": "https://y5w8j4a9.ssl.hwcdn.net/andflixhd/tracks-v1a1/index.m3u8", 10 | "category": "Movies" 11 | }, 12 | { 13 | "name": "&privé HD", 14 | "logo": "https://upload.wikimedia.org/wikipedia/en/4/4f/Logo_of_%26_Priv%C3%A9_HD.jpg", 15 | "type":"m38u", 16 | "url": "https://y5w8j4a9.ssl.hwcdn.net/andprivehd/tracks-v1a1/index.m3u8", 17 | "category": "Movies" 18 | }, 19 | { 20 | "name": "3 Tamil TV", 21 | "logo": "https://i.imgur.com/WfAU7pB.png", 22 | "type":"m38u", 23 | "url": "https://6n3yogbnd9ok-hls-live.5centscdn.com/threetamil/d0dbe915091d400bd8ee7f27f0791303.sdp/index.m3u8", 24 | "category": "Entertainment" 25 | }, 26 | 27 | { 28 | "name": "7X Music", 29 | "logo": "https://i.imgur.com/fD7wLka.jpg", 30 | "type":"m38u", 31 | "url": "http://newsjatt.camdvr.org:1935/newsjatt/myStream/playlist.m3u8", 32 | "category": "Music" 33 | }, 34 | { 35 | "name": "9XM", 36 | "logo": "https://i.imgur.com/fD7wLka.jpg", 37 | "type":"m38u", 38 | "url": "https://d2q8p4pe5spbak.cloudfront.net/bpk-tv/9XM/9XM.isml/index.m3u8", 39 | "category": "Music" 40 | }, 41 | 42 | { 43 | "name": "Aaj Tak", 44 | "logo": "https://upload.wikimedia.org/wikipedia/commons/a/ab/AT-New-Logo-800x600.png", 45 | "type":"m38u", 46 | "url": "https://feeds.intoday.in/aajtak/api/aajtakhd/master.m3u8", 47 | "category": "News" 48 | }, 49 | { 50 | "name": "Aaj Tak (560p)", 51 | "logo": "https://upload.wikimedia.org/wikipedia/commons/a/ab/AT-New-Logo-800x600.png", 52 | "type":"m38u", 53 | "url": "https://lmil.live-s.cdn.bitgravity.com/cdn-live/_definst_/lmil/live/aajtak_app.smil/playlist.m3u8", 54 | "category": "News" 55 | }, 56 | { 57 | "name": "Aathavan TV", 58 | "logo": "https://i.imgur.com/IgwQ7o5.png", 59 | "type":"m38u", 60 | "language":"Tamil", 61 | "url": "http://45.77.66.224:1935/athavantv/live/playlist.m3u8", 62 | "category": "Entertainment" 63 | }, 64 | 65 | { 66 | "name": "ABP Ananda", 67 | "logo": "https://tv.releasemyad.com/images/logo/20160108044853abp-ananada.jpg", 68 | "type":"m38u", 69 | "language":"Hindi", 70 | "url": "https://abp-i.akamaihd.net/hls/live/765530/abpananda/master.m3u8", 71 | "category": "News" 72 | }, 73 | 74 | { 75 | "name": "ABP Ananda(720p)", 76 | "logo": "https://tv.releasemyad.com/images/logo/20160108044853abp-ananada.jpg", 77 | "type":"m38u", 78 | "url": "https://d3pnfn2zxtq6km.cloudfront.net/out/v1/c77a35d9d4f74371a3cf0f214a9eb8c0/index.m3u8", 79 | "category": "News" 80 | }, 81 | 82 | 83 | { 84 | "name": "ABP Asmita(324p)", 85 | "logo": "https://upload.wikimedia.org/wikipedia/en/4/42/ABP_Asmita_Logo.png", 86 | "type":"m38u", 87 | "language":"Gujrati", 88 | "url": "http://abpasmita-lh.akamaihd.net:80/i/abpasmita_1@77821/master.m3u8", 89 | "category": "News" 90 | }, 91 | 92 | 93 | 94 | 95 | { 96 | "name": "ABP Asmita(720p)", 97 | "logo": "https://upload.wikimedia.org/wikipedia/en/4/42/ABP_Asmita_Logo.png", 98 | "type":"m38u", 99 | "language":"Gujrati", 100 | "url": "https://abp-i.akamaihd.net/hls/live/765532/abpasmita/master.m3u8", 101 | "category": "News" 102 | }, 103 | 104 | 105 | { 106 | "name": "ABP Asmita", 107 | "logo": "https://upload.wikimedia.org/wikipedia/en/4/42/ABP_Asmita_Logo.png", 108 | "type":"m38u", 109 | "language":"Gujrati", 110 | "url": "https://abpasmita-lh.akamaihd.net/i/abpasmita_1@77821/master.m3u8", 111 | "category": "News" 112 | }, 113 | 114 | { 115 | "name": "ABP News(324p)", 116 | "logo": "https://static.abplive.in/wp-content/themes/abp-hindi/images/logo/hindiLogoD.png", 117 | "type":"m38u", 118 | "language":"English", 119 | "url": "http://hindiabp-lh.akamaihd.net/i/hindiabp1new_1@192103/master.m3u8", 120 | "category": "News" 121 | }, 122 | 123 | 124 | 125 | 126 | 127 | { 128 | "name": "ABP Majha", 129 | "logo": "https://upload.wikimedia.org/wikipedia/en/5/5a/ABP_Majha_Logo.png", 130 | "type":"m38u", 131 | "language":"Hindi", 132 | "url": "https://abp-i.akamaihd.net/hls/live/765531/abpmajha/master.m3u8", 133 | "category": "News" 134 | }, 135 | 136 | 137 | 138 | { 139 | "name": "ABP News(720p)", 140 | "logo": "https://static.abplive.in/wp-content/themes/abp-hindi/images/logo/hindiLogoD.png", 141 | "type":"m38u", 142 | "language":"English", 143 | "url": "https://abp-i.akamaihd.net/hls/live/765529/abphindi/master.m3u8", 144 | "category": "News" 145 | }, 146 | 147 | ] ; 148 | 149 | 150 | 151 | router.get('/', async (req,res) => { 152 | if(req.Auth){ 153 | try { 154 | res.status('200').send(resJson_IndianChannelList); 155 | } catch (error) { 156 | res.status('500').send('Server error'); 157 | } 158 | 159 | } 160 | else{ 161 | res.status('400').send('Auth fail'); 162 | } 163 | 164 | 165 | }); 166 | 167 | 168 | module.exports = router; -------------------------------------------------------------------------------- /lavender_app/lib/presentation/pages/movies/movie_detail_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | import '../../../data/movies/movies.dart'; 5 | import '../../../utils/constants.dart'; 6 | import '../../widgets/widget_information_box.dart'; 7 | import '../view_media_page.dart'; 8 | 9 | class MovieDetailPage extends StatefulWidget { 10 | final Movie movie; 11 | const MovieDetailPage({Key key, @required this.movie}) : super(key: key); 12 | 13 | @override 14 | _MovieDetailPageState createState() => _MovieDetailPageState(); 15 | } 16 | 17 | class _MovieDetailPageState extends State { 18 | static const String language = 'Language: '; 19 | static const String description = 'Description: '; 20 | static const String play = 'Play'; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | final double height = MediaQuery.of(context).size.height; 25 | final double width = MediaQuery.of(context).size.width; 26 | return Scaffold( 27 | body: SafeArea( 28 | child: SingleChildScrollView( 29 | child: Column( 30 | children: [ 31 | Container( 32 | width: width, 33 | height: height * 0.4, 34 | decoration: BoxDecoration( 35 | image: DecorationImage( 36 | image: NetworkImage(widget.movie.logo), 37 | fit: BoxFit.cover, 38 | colorFilter: ColorFilter.mode( 39 | Colors.black.withOpacity(0.2), BlendMode.dstATop), 40 | ), 41 | ), 42 | child: Column( 43 | crossAxisAlignment: CrossAxisAlignment.start, 44 | children: [ 45 | GestureDetector( 46 | onTap: () => Navigator.of(context).pop(), 47 | child: Container( 48 | margin: const EdgeInsets.all(10.0), 49 | padding: const EdgeInsets.all(8.0), 50 | decoration: BoxDecoration( 51 | color: whiteColor, 52 | shape: BoxShape.circle, 53 | ), 54 | child: const Icon( 55 | CupertinoIcons.back, 56 | color: Colors.black, 57 | ), 58 | ), 59 | ), 60 | sized50, 61 | Column( 62 | children: [ 63 | Container( 64 | width: width, 65 | child: Center( 66 | child: Text( 67 | widget.movie.name, 68 | style: const TextStyle( 69 | color: Colors.white, 70 | fontWeight: FontWeight.w600, 71 | fontSize: 24.0), 72 | ), 73 | ), 74 | ), 75 | ], 76 | ), 77 | height < 680 ? sized40 : sized50, 78 | Container( 79 | width: width, 80 | child: Center( 81 | child: GestureDetector( 82 | onTap: () { 83 | Navigator.of(context) 84 | .push(MaterialPageRoute(builder: (context) { 85 | return ViewMediaPage(source: widget.movie.url); 86 | })); 87 | }, 88 | child: Container( 89 | width: width * 0.5, 90 | height: height * 0.05, 91 | decoration: BoxDecoration( 92 | borderRadius: BorderRadius.circular(20.0), 93 | color: Colors.redAccent), 94 | child: Center( 95 | child: Row( 96 | mainAxisSize: MainAxisSize.min, 97 | mainAxisAlignment: MainAxisAlignment.center, 98 | crossAxisAlignment: CrossAxisAlignment.center, 99 | children: const [ 100 | sized50, 101 | const Icon(CupertinoIcons.play), 102 | sized50, 103 | const Text( 104 | play, 105 | ), 106 | sized50 107 | ], 108 | ), 109 | ), 110 | ), 111 | ), 112 | ), 113 | ), 114 | ], 115 | ), 116 | ), 117 | sized30, 118 | WidgetInformationBox( 119 | width: width, 120 | text: widget.movie.language, 121 | title: language, 122 | ), 123 | sized10, 124 | WidgetInformationBox( 125 | width: width, 126 | text: widget.movie.description, 127 | title: description, 128 | ), 129 | ], 130 | ), 131 | ), 132 | ), 133 | ); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /lavender_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | {"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"idiom":"watch","filename":"172.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"86x86","expected-size":"172","role":"quickLook"},{"idiom":"watch","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"40x40","expected-size":"80","role":"appLauncher"},{"idiom":"watch","filename":"88.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"40mm","scale":"2x","size":"44x44","expected-size":"88","role":"appLauncher"},{"idiom":"watch","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"44mm","scale":"2x","size":"50x50","expected-size":"100","role":"appLauncher"},{"idiom":"watch","filename":"196.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"42mm","scale":"2x","size":"98x98","expected-size":"196","role":"quickLook"},{"idiom":"watch","filename":"216.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"44mm","scale":"2x","size":"108x108","expected-size":"216","role":"quickLook"},{"idiom":"watch","filename":"48.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"24x24","expected-size":"48","role":"notificationCenter"},{"idiom":"watch","filename":"55.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"42mm","scale":"2x","size":"27.5x27.5","expected-size":"55","role":"notificationCenter"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch","role":"companionSettings","scale":"3x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch","role":"companionSettings","scale":"2x"},{"size":"1024x1024","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch-marketing","scale":"1x"},{"size":"128x128","expected-size":"128","filename":"128.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"256x256","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"128x128","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"256x256","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"512x512","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"16","filename":"16.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"64","filename":"64.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"512x512","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"}]} -------------------------------------------------------------------------------- /lavender_app/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | archive: 5 | dependency: transitive 6 | description: 7 | name: archive 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "3.1.2" 11 | async: 12 | dependency: transitive 13 | description: 14 | name: async 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.6.1" 18 | bloc: 19 | dependency: transitive 20 | description: 21 | name: bloc 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "7.0.0" 25 | boolean_selector: 26 | dependency: transitive 27 | description: 28 | name: boolean_selector 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.1.0" 32 | characters: 33 | dependency: transitive 34 | description: 35 | name: characters 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0" 39 | charcode: 40 | dependency: transitive 41 | description: 42 | name: charcode 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.2.0" 46 | clock: 47 | dependency: transitive 48 | description: 49 | name: clock 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.1.0" 53 | collection: 54 | dependency: transitive 55 | description: 56 | name: collection 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.15.0" 60 | crypto: 61 | dependency: transitive 62 | description: 63 | name: crypto 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "3.0.1" 67 | csslib: 68 | dependency: transitive 69 | description: 70 | name: csslib 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "0.16.2" 74 | cupertino_icons: 75 | dependency: "direct main" 76 | description: 77 | name: cupertino_icons 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "1.0.3" 81 | equatable: 82 | dependency: "direct main" 83 | description: 84 | name: equatable 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "2.0.0" 88 | fake_async: 89 | dependency: transitive 90 | description: 91 | name: fake_async 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "1.2.0" 95 | ffi: 96 | dependency: transitive 97 | description: 98 | name: ffi 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "1.0.0" 102 | file: 103 | dependency: transitive 104 | description: 105 | name: file 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "6.1.0" 109 | flutter: 110 | dependency: "direct main" 111 | description: flutter 112 | source: sdk 113 | version: "0.0.0" 114 | flutter_bloc: 115 | dependency: "direct main" 116 | description: 117 | name: flutter_bloc 118 | url: "https://pub.dartlang.org" 119 | source: hosted 120 | version: "7.0.0" 121 | flutter_test: 122 | dependency: "direct dev" 123 | description: flutter 124 | source: sdk 125 | version: "0.0.0" 126 | flutter_web_plugins: 127 | dependency: transitive 128 | description: flutter 129 | source: sdk 130 | version: "0.0.0" 131 | html: 132 | dependency: transitive 133 | description: 134 | name: html 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "0.14.0+4" 138 | http: 139 | dependency: "direct main" 140 | description: 141 | name: http 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "0.12.2" 145 | http_parser: 146 | dependency: transitive 147 | description: 148 | name: http_parser 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "3.1.4" 152 | import_js_library: 153 | dependency: transitive 154 | description: 155 | name: import_js_library 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "1.0.2" 159 | js: 160 | dependency: transitive 161 | description: 162 | name: js 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "0.6.3" 166 | logging: 167 | dependency: transitive 168 | description: 169 | name: logging 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "1.0.1" 173 | lottie: 174 | dependency: "direct main" 175 | description: 176 | name: lottie 177 | url: "https://pub.dartlang.org" 178 | source: hosted 179 | version: "1.0.1" 180 | matcher: 181 | dependency: transitive 182 | description: 183 | name: matcher 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "0.12.10" 187 | meta: 188 | dependency: transitive 189 | description: 190 | name: meta 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "1.3.0" 194 | nested: 195 | dependency: transitive 196 | description: 197 | name: nested 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "1.0.0" 201 | orientation: 202 | dependency: transitive 203 | description: 204 | name: orientation 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "1.3.0" 208 | path: 209 | dependency: transitive 210 | description: 211 | name: path 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "1.8.0" 215 | path_provider: 216 | dependency: transitive 217 | description: 218 | name: path_provider 219 | url: "https://pub.dartlang.org" 220 | source: hosted 221 | version: "1.6.28" 222 | path_provider_linux: 223 | dependency: transitive 224 | description: 225 | name: path_provider_linux 226 | url: "https://pub.dartlang.org" 227 | source: hosted 228 | version: "0.0.1+2" 229 | path_provider_macos: 230 | dependency: transitive 231 | description: 232 | name: path_provider_macos 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "0.0.4+8" 236 | path_provider_platform_interface: 237 | dependency: transitive 238 | description: 239 | name: path_provider_platform_interface 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "1.0.4" 243 | path_provider_windows: 244 | dependency: transitive 245 | description: 246 | name: path_provider_windows 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "0.0.5" 250 | pedantic: 251 | dependency: transitive 252 | description: 253 | name: pedantic 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "1.11.0" 257 | platform: 258 | dependency: transitive 259 | description: 260 | name: platform 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "3.0.0" 264 | plugin_platform_interface: 265 | dependency: transitive 266 | description: 267 | name: plugin_platform_interface 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "1.0.3" 271 | process: 272 | dependency: transitive 273 | description: 274 | name: process 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "4.2.1" 278 | provider: 279 | dependency: transitive 280 | description: 281 | name: provider 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "5.0.0" 285 | screen: 286 | dependency: transitive 287 | description: 288 | name: screen 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "0.0.5" 292 | sky_engine: 293 | dependency: transitive 294 | description: flutter 295 | source: sdk 296 | version: "0.0.99" 297 | source_span: 298 | dependency: transitive 299 | description: 300 | name: source_span 301 | url: "https://pub.dartlang.org" 302 | source: hosted 303 | version: "1.8.1" 304 | stack_trace: 305 | dependency: transitive 306 | description: 307 | name: stack_trace 308 | url: "https://pub.dartlang.org" 309 | source: hosted 310 | version: "1.10.0" 311 | stream_channel: 312 | dependency: transitive 313 | description: 314 | name: stream_channel 315 | url: "https://pub.dartlang.org" 316 | source: hosted 317 | version: "2.1.0" 318 | string_scanner: 319 | dependency: transitive 320 | description: 321 | name: string_scanner 322 | url: "https://pub.dartlang.org" 323 | source: hosted 324 | version: "1.1.0" 325 | term_glyph: 326 | dependency: transitive 327 | description: 328 | name: term_glyph 329 | url: "https://pub.dartlang.org" 330 | source: hosted 331 | version: "1.2.0" 332 | test_api: 333 | dependency: transitive 334 | description: 335 | name: test_api 336 | url: "https://pub.dartlang.org" 337 | source: hosted 338 | version: "0.3.0" 339 | typed_data: 340 | dependency: transitive 341 | description: 342 | name: typed_data 343 | url: "https://pub.dartlang.org" 344 | source: hosted 345 | version: "1.3.0" 346 | vector_math: 347 | dependency: transitive 348 | description: 349 | name: vector_math 350 | url: "https://pub.dartlang.org" 351 | source: hosted 352 | version: "2.1.0" 353 | video_player: 354 | dependency: transitive 355 | description: 356 | name: video_player 357 | url: "https://pub.dartlang.org" 358 | source: hosted 359 | version: "0.11.1+5" 360 | video_player_platform_interface: 361 | dependency: transitive 362 | description: 363 | name: video_player_platform_interface 364 | url: "https://pub.dartlang.org" 365 | source: hosted 366 | version: "2.2.0" 367 | video_player_web: 368 | dependency: transitive 369 | description: 370 | name: video_player_web 371 | url: "https://pub.dartlang.org" 372 | source: hosted 373 | version: "0.1.4+1" 374 | video_player_web_hls: 375 | dependency: transitive 376 | description: 377 | name: video_player_web_hls 378 | url: "https://pub.dartlang.org" 379 | source: hosted 380 | version: "0.1.8" 381 | wakelock: 382 | dependency: transitive 383 | description: 384 | name: wakelock 385 | url: "https://pub.dartlang.org" 386 | source: hosted 387 | version: "0.2.1+1" 388 | wakelock_platform_interface: 389 | dependency: transitive 390 | description: 391 | name: wakelock_platform_interface 392 | url: "https://pub.dartlang.org" 393 | source: hosted 394 | version: "0.1.0+1" 395 | wakelock_web: 396 | dependency: transitive 397 | description: 398 | name: wakelock_web 399 | url: "https://pub.dartlang.org" 400 | source: hosted 401 | version: "0.1.0+3" 402 | win32: 403 | dependency: transitive 404 | description: 405 | name: win32 406 | url: "https://pub.dartlang.org" 407 | source: hosted 408 | version: "2.0.5" 409 | xdg_directories: 410 | dependency: transitive 411 | description: 412 | name: xdg_directories 413 | url: "https://pub.dartlang.org" 414 | source: hosted 415 | version: "0.1.2" 416 | yoyo_player: 417 | dependency: "direct main" 418 | description: 419 | name: yoyo_player 420 | url: "https://pub.dartlang.org" 421 | source: hosted 422 | version: "0.1.0" 423 | sdks: 424 | dart: ">=2.12.0 <3.0.0" 425 | flutter: ">=2.0.1" 426 | --------------------------------------------------------------------------------