diff --git a/.gitignore b/.gitignore
index 24476c5..c892a5a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,9 @@ migrate_working_dir/
.pub-cache/
.pub/
/build/
+*.g.dart
+*.gen.dart
+pubspec.lock
# Symbolication related
app.*.symbols
diff --git a/README.md b/README.md
index 6830e95..9635367 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,23 @@
# flutter_movie_clean
A sample Flutter application follow clean architecture
+
+## Installation
+Clone this repository
+```bash
+git clone git@github.com:namnh-0652/flutter_movie_clean.git
+```
+Install Pub
+```bash
+flutter clean
+flutter pub get
+```
+
+Run command to add file `locale_keys.g.dart`, this file support for library `easy_localization`
+```bash
+flutter pub run easy_localization:generate -S assets/translations -f keys -o locale_keys.g.dart
+```
+
+Run command to run code generator for your assets, fonts, colors... by `FlutterGen`
+```bash
+flutter packages pub run build_runner build
+```
diff --git a/assets/color/colors.xml b/assets/color/colors.xml
new file mode 100644
index 0000000..e584525
--- /dev/null
+++ b/assets/color/colors.xml
@@ -0,0 +1,4 @@
+
+
+ #ED1B24
+
diff --git a/assets/images/bg_profile.png b/assets/images/bg_profile.png
new file mode 100644
index 0000000..52b2aec
Binary files /dev/null and b/assets/images/bg_profile.png differ
diff --git a/assets/images/icons/ic_categories.png b/assets/images/icons/ic_categories.png
new file mode 100644
index 0000000..94f95fa
Binary files /dev/null and b/assets/images/icons/ic_categories.png differ
diff --git a/assets/images/icons/ic_downloads.png b/assets/images/icons/ic_downloads.png
new file mode 100644
index 0000000..dc8fa25
Binary files /dev/null and b/assets/images/icons/ic_downloads.png differ
diff --git a/assets/images/icons/ic_home.png b/assets/images/icons/ic_home.png
new file mode 100644
index 0000000..afd1db9
Binary files /dev/null and b/assets/images/icons/ic_home.png differ
diff --git a/assets/images/icons/ic_more.png b/assets/images/icons/ic_more.png
new file mode 100644
index 0000000..ae31d53
Binary files /dev/null and b/assets/images/icons/ic_more.png differ
diff --git a/assets/images/marvel_logo.png b/assets/images/marvel_logo.png
new file mode 100644
index 0000000..81ebc0d
Binary files /dev/null and b/assets/images/marvel_logo.png differ
diff --git a/assets/images/movies/movies1.png b/assets/images/movies/movies1.png
new file mode 100644
index 0000000..b9eed26
Binary files /dev/null and b/assets/images/movies/movies1.png differ
diff --git a/assets/images/movies/movies2.png b/assets/images/movies/movies2.png
new file mode 100644
index 0000000..4949d68
Binary files /dev/null and b/assets/images/movies/movies2.png differ
diff --git a/assets/images/movies/movies3.png b/assets/images/movies/movies3.png
new file mode 100644
index 0000000..f6aa657
Binary files /dev/null and b/assets/images/movies/movies3.png differ
diff --git a/assets/images/onboardings/poster1.jpeg b/assets/images/onboardings/poster1.jpeg
new file mode 100644
index 0000000..c939a77
Binary files /dev/null and b/assets/images/onboardings/poster1.jpeg differ
diff --git a/assets/images/onboardings/poster2.jpeg b/assets/images/onboardings/poster2.jpeg
new file mode 100644
index 0000000..e98570f
Binary files /dev/null and b/assets/images/onboardings/poster2.jpeg differ
diff --git a/assets/images/onboardings/poster3.jpeg b/assets/images/onboardings/poster3.jpeg
new file mode 100644
index 0000000..92589b9
Binary files /dev/null and b/assets/images/onboardings/poster3.jpeg differ
diff --git a/assets/images/onboardings/poster4.jpeg b/assets/images/onboardings/poster4.jpeg
new file mode 100644
index 0000000..a80118e
Binary files /dev/null and b/assets/images/onboardings/poster4.jpeg differ
diff --git a/assets/images/onboardings/poster5.jpeg b/assets/images/onboardings/poster5.jpeg
new file mode 100644
index 0000000..0be770e
Binary files /dev/null and b/assets/images/onboardings/poster5.jpeg differ
diff --git a/assets/images/onboardings/poster6.jpeg b/assets/images/onboardings/poster6.jpeg
new file mode 100644
index 0000000..4f24616
Binary files /dev/null and b/assets/images/onboardings/poster6.jpeg differ
diff --git a/assets/images/profile_avatar.png b/assets/images/profile_avatar.png
new file mode 100644
index 0000000..053d390
Binary files /dev/null and b/assets/images/profile_avatar.png differ
diff --git a/assets/images/series/series1.png b/assets/images/series/series1.png
new file mode 100644
index 0000000..635cc6b
Binary files /dev/null and b/assets/images/series/series1.png differ
diff --git a/assets/images/series/series2.png b/assets/images/series/series2.png
new file mode 100644
index 0000000..559a77b
Binary files /dev/null and b/assets/images/series/series2.png differ
diff --git a/assets/images/series/series3.png b/assets/images/series/series3.png
new file mode 100644
index 0000000..f953d81
Binary files /dev/null and b/assets/images/series/series3.png differ
diff --git a/assets/images/trendings/trending_1.png b/assets/images/trendings/trending_1.png
new file mode 100644
index 0000000..40ebe7e
Binary files /dev/null and b/assets/images/trendings/trending_1.png differ
diff --git a/assets/images/trendings/trending_2.png b/assets/images/trendings/trending_2.png
new file mode 100644
index 0000000..e56ed74
Binary files /dev/null and b/assets/images/trendings/trending_2.png differ
diff --git a/assets/images/trendings/trending_3.png b/assets/images/trendings/trending_3.png
new file mode 100644
index 0000000..262c398
Binary files /dev/null and b/assets/images/trendings/trending_3.png differ
diff --git a/assets/images/trendings/trending_4.png b/assets/images/trendings/trending_4.png
new file mode 100644
index 0000000..bb12558
Binary files /dev/null and b/assets/images/trendings/trending_4.png differ
diff --git a/assets/translations/en.json b/assets/translations/en.json
new file mode 100644
index 0000000..42e64d2
--- /dev/null
+++ b/assets/translations/en.json
@@ -0,0 +1,19 @@
+{
+ "continueOnBoarding": "Continue",
+ "login": "Login",
+ "signup": "Signup",
+ "onBoardingPageFirstTitle": "All your favorite \n MARVEL Movies & Series \n at one place",
+ "onBoardingPageSecondTitle": "Watch Online \n or \n Download Offline",
+ "onBoardingPageThirdTitle": "Create profiles for \n different members & \n get personalised \n recommendations",
+ "onBoardingPageFourthTitle": "Plans according to your \n needs at affordable \n prices",
+ "onBoardingPageFifthTitle": "Let's Get Started !!!",
+ "home": "Home",
+ "categories": "Categories",
+ "downloads": "Downloads",
+ "more": "More",
+ "latestMovies": "Latest Movies",
+ "latestSeries": "Latest Series",
+ "trendingToday": "Trending Today",
+ "oldMovies": "Old Movies",
+ "oldSeries": "Old Series"
+}
diff --git a/assets/translations/vi.json b/assets/translations/vi.json
new file mode 100644
index 0000000..6832733
--- /dev/null
+++ b/assets/translations/vi.json
@@ -0,0 +1,19 @@
+{
+ "continueOnBoarding": "Tiếp tục",
+ "login": "Đăng nhập",
+ "signup": "Đăng ký",
+ "onBoardingPageFirstTitle": "Tất cả \n phim MARVEL & Series \n tại một nơi",
+ "onBoardingPageSecondTitle": "Xem trực tuyến \n hoặc \n tải xuống ngoại tuyến",
+ "onBoardingPageThirdTitle": "Tạo hồ sơ cho \n các thành viên khác nhau & \n nhận đề xuất \n được cá nhân hóa",
+ "onBoardingPageFourthTitle": "Các gói theo nhu cầu của bạn \n với mức giá phải chăng",
+ "onBoardingPageFifthTitle": "Bắt đầu thôi !!!",
+ "home": "Trang chủ",
+ "categories": "Thể loại",
+ "downloads": "Tải xuống",
+ "more": "Thêm",
+ "latestMovies": "Những Bộ Phim Gần Đây",
+ "latestSeries": "Sê-ri Mới Nhất",
+ "trendingToday": "Xu Hướng Hôm Nay",
+ "oldMovies": "Những Bộ Phim Cũ",
+ "oldSeries": "Sê-ri Cũ"
+}
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 6397623..b36673f 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -4,6 +4,13 @@
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
+
+ CFBundleLocalizations
+
+ en
+ vi
+
+
CFBundleDisplayName
Flutter Movie Clean
CFBundleExecutable
diff --git a/lib/bloc_observer.dart b/lib/bloc_observer.dart
new file mode 100644
index 0000000..efdb35d
--- /dev/null
+++ b/lib/bloc_observer.dart
@@ -0,0 +1,29 @@
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class AppBlocObserver extends BlocObserver {
+ const AppBlocObserver();
+
+ @override
+ void onEvent(Bloc bloc, Object? event) {
+ super.onEvent(bloc, event);
+ print(event);
+ }
+
+ @override
+ void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
+ super.onError(bloc, error, stackTrace);
+ print(error);
+ }
+
+ @override
+ void onChange(BlocBase bloc, Change change) {
+ super.onChange(bloc, change);
+ print(change);
+ }
+
+ @override
+ void onTransition(Bloc bloc, Transition transition) {
+ super.onTransition(bloc, transition);
+ print(transition);
+ }
+}
diff --git a/lib/categories/categories.dart b/lib/categories/categories.dart
new file mode 100644
index 0000000..2a5ae81
--- /dev/null
+++ b/lib/categories/categories.dart
@@ -0,0 +1,10 @@
+import 'package:flutter/material.dart';
+
+class CategoriesScreen extends StatelessWidget {
+ const CategoriesScreen({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return const Center(child: Text("Categories"),);
+ }
+}
diff --git a/lib/downloads/downloads.dart b/lib/downloads/downloads.dart
new file mode 100644
index 0000000..bfc4264
--- /dev/null
+++ b/lib/downloads/downloads.dart
@@ -0,0 +1,10 @@
+import 'package:flutter/material.dart';
+
+class DownloadsScreen extends StatelessWidget {
+ const DownloadsScreen({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return const Center(child: Text("Download"),);
+ }
+}
diff --git a/lib/exports/screens.dart b/lib/exports/screens.dart
new file mode 100644
index 0000000..2cedf95
--- /dev/null
+++ b/lib/exports/screens.dart
@@ -0,0 +1,6 @@
+export '/categories/categories.dart';
+export '/downloads/downloads.dart';
+export '/home/home_page.dart';
+export '/more/more.dart';
+export '/moviedetails/movie_details.dart';
+export '/onboarding/on_boarding.dart';
diff --git a/lib/home/components/carousel_slider_shader.dart b/lib/home/components/carousel_slider_shader.dart
new file mode 100644
index 0000000..bec82b1
--- /dev/null
+++ b/lib/home/components/carousel_slider_shader.dart
@@ -0,0 +1,51 @@
+import 'package:carousel_slider/carousel_slider.dart';
+import 'package:flutter/material.dart';
+
+class CarouselSliderShaderWidget extends StatelessWidget {
+ const CarouselSliderShaderWidget({
+ super.key,
+ required List paths, required this.onItemTapped,
+ }) : _paths = paths;
+
+ final Gradient _maskingGradient = const LinearGradient(
+ colors: [
+ Colors.black,
+ Colors.transparent,
+ ],
+ stops: [0.0, 0.4],
+ tileMode: TileMode.mirror,
+ begin: Alignment.centerLeft,
+ end: Alignment.center,
+ );
+ final List _paths;
+ final Function(int index) onItemTapped;
+
+ @override
+ Widget build(BuildContext context) {
+ return ShaderMask(
+ shaderCallback: (bounds) => _maskingGradient.createShader(bounds),
+ blendMode: BlendMode.darken,
+ child: CarouselSlider(
+ options: CarouselOptions(
+ height: 173.0,
+ enlargeFactor: 0.2,
+ viewportFraction: 0.7,
+ enlargeCenterPage: true,
+ ),
+ items: _paths.map((path) {
+ return Builder(builder: (BuildContext context) {
+ return GestureDetector(
+ child: Container(
+ width: MediaQuery.of(context).size.width,
+ margin: const EdgeInsets.symmetric(horizontal: 6.0),
+ decoration: const BoxDecoration(color: Colors.amber),
+ child: Image.asset(path, fit: BoxFit.fill),
+ ),
+ onTap: () {onItemTapped(_paths.indexOf(path));},
+ );
+ });
+ }).toList(),
+ ),
+ );
+ }
+}
diff --git a/lib/home/components/horizontal_movie_list_view.dart b/lib/home/components/horizontal_movie_list_view.dart
new file mode 100644
index 0000000..2d32984
--- /dev/null
+++ b/lib/home/components/horizontal_movie_list_view.dart
@@ -0,0 +1,40 @@
+import 'package:flutter/material.dart';
+
+class HorizontalMoviesListView extends StatelessWidget {
+ const HorizontalMoviesListView({
+ super.key,
+ required List paths,
+ required this.itemWidth,
+ required this.itemHeight,
+ required this.onItemTapped,
+ }) : _paths = paths;
+
+ final List _paths;
+ final double itemWidth;
+ final double itemHeight;
+ final Function(int index) onItemTapped;
+
+ @override
+ Widget build(BuildContext context) {
+ return ListView.builder(
+ physics: const ClampingScrollPhysics(),
+ shrinkWrap: true,
+ scrollDirection: Axis.horizontal,
+ itemCount: _paths.length,
+ itemBuilder: (BuildContext context, int index) => Padding(
+ padding: const EdgeInsets.only(
+ left: 12.0,
+ ),
+ child: GestureDetector(
+ child: Image.asset(
+ _paths.elementAt(index),
+ fit: BoxFit.cover,
+ width: itemWidth,
+ height: itemHeight,
+ ),
+ onTap: () => {onItemTapped(index)},
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/home/cubit/home_cubit.dart b/lib/home/cubit/home_cubit.dart
new file mode 100644
index 0000000..6a18f4b
--- /dev/null
+++ b/lib/home/cubit/home_cubit.dart
@@ -0,0 +1,6 @@
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_movie_clean/home/cubit/home_state.dart';
+
+class HomeCubit extends Cubit {
+ HomeCubit() : super(HomeState());
+}
diff --git a/lib/home/cubit/home_state.dart b/lib/home/cubit/home_state.dart
new file mode 100644
index 0000000..7aad774
--- /dev/null
+++ b/lib/home/cubit/home_state.dart
@@ -0,0 +1,28 @@
+import '../../generated/assets.gen.dart';
+
+class HomeState {
+ HomeState();
+
+ final List moviesPaths = [
+ Assets.images.movies.movies1.path,
+ Assets.images.movies.movies2.path,
+ Assets.images.movies.movies3.path,
+ ];
+
+ final List seriesPaths = [
+ Assets.images.series.series1.path,
+ Assets.images.series.series2.path,
+ Assets.images.series.series3.path,
+ ];
+
+ final List trendingPaths = [
+ Assets.images.trendings.trending1.path,
+ Assets.images.trendings.trending2.path,
+ Assets.images.trendings.trending3.path,
+ Assets.images.trendings.trending4.path,
+ Assets.images.trendings.trending1.path,
+ Assets.images.trendings.trending2.path,
+ Assets.images.trendings.trending3.path,
+ Assets.images.trendings.trending4.path,
+ ];
+}
diff --git a/lib/home/home_page.dart b/lib/home/home_page.dart
new file mode 100644
index 0000000..5ca06ae
--- /dev/null
+++ b/lib/home/home_page.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'cubit/home_cubit.dart';
+import 'home_view.dart';
+
+class HomeScreen extends StatelessWidget {
+ const HomeScreen({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocProvider(
+ create: (_) => HomeCubit(),
+ child: const HomeView(),
+ );
+ }
+}
diff --git a/lib/home/home_view.dart b/lib/home/home_view.dart
new file mode 100644
index 0000000..808d920
--- /dev/null
+++ b/lib/home/home_view.dart
@@ -0,0 +1,109 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_movie_clean/widgets/header_widget.dart';
+import 'package:go_router/go_router.dart';
+
+import '../generated/locale_keys.g.dart';
+import 'components/carousel_slider_shader.dart';
+import 'components/horizontal_movie_list_view.dart';
+import 'cubit/home_cubit.dart';
+
+class HomeView extends StatelessWidget {
+ const HomeView({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ final state = BlocProvider.of(context, listen: false).state;
+ return SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(height: 16.0),
+ HeaderWidget(onProfileTapped: () {}),
+ Padding(
+ padding: const EdgeInsets.only(left: 12.0, bottom: 14.0),
+ child: Text(
+ LocaleKeys.latestMovies.tr(),
+ style: Theme.of(context).textTheme.titleLarge,
+ ),
+ ),
+ CarouselSliderShaderWidget(
+ paths: state.moviesPaths,
+ onItemTapped: (int index) {
+ context.go(context.namedLocation('movie_details'));
+ },
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 24.0, left: 12.0, bottom: 14.0),
+ child: Text(
+ LocaleKeys.latestSeries.tr(),
+ style: Theme.of(context).textTheme.titleLarge,
+ ),
+ ),
+ CarouselSliderShaderWidget(
+ paths: state.seriesPaths,
+ onItemTapped: (int index) {
+ context.go(context.namedLocation('movie_details'));
+ },
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 24.0, left: 12.0, bottom: 14.0),
+ child: Text(
+ LocaleKeys.trendingToday.tr(),
+ style: Theme.of(context).textTheme.titleLarge,
+ ),
+ ),
+ SizedBox(
+ height: 150.0,
+ child: HorizontalMoviesListView(
+ paths: state.trendingPaths,
+ itemWidth: 100.0,
+ itemHeight: 150.0,
+ onItemTapped: (int index) {
+ context.go(context.namedLocation('movie_details'));
+ },
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 24.0, left: 12.0, bottom: 14.0),
+ child: Text(
+ LocaleKeys.oldMovies.tr(),
+ style: Theme.of(context).textTheme.titleLarge,
+ ),
+ ),
+ SizedBox(
+ height: 150.0,
+ child: HorizontalMoviesListView(
+ paths: state.trendingPaths,
+ itemWidth: 100.0,
+ itemHeight: 150.0,
+ onItemTapped: (int index) {
+ context.go(context.namedLocation('movie_details'));
+ },
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 24.0, left: 12.0, bottom: 14.0),
+ child: Text(
+ LocaleKeys.oldSeries.tr(),
+ style: Theme.of(context).textTheme.titleLarge,
+ ),
+ ),
+ SizedBox(
+ height: 60.0,
+ child: HorizontalMoviesListView(
+ paths: state.trendingPaths,
+ itemWidth: 100.0,
+ itemHeight: 60.0,
+ onItemTapped: (int index) {
+ context.go(context.namedLocation('movie_details'));
+ },
+ ),
+ ),
+ const SizedBox(height: 65.0),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/main.dart b/lib/main.dart
index 008fa38..9370f04 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,115 +1,41 @@
+import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
-
-void main() {
- runApp(const MyApp());
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_movie_clean/bloc_observer.dart';
+import 'package:flutter_movie_clean/theme/app_theme.dart';
+
+import 'router/router.dart';
+
+void main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+ Bloc.observer = const AppBlocObserver();
+
+ await EasyLocalization.ensureInitialized();
+ const supportedLocales = [Locale('en'), Locale('vi')];
+ runApp(
+ EasyLocalization(
+ supportedLocales: supportedLocales,
+ path: 'assets/translations',
+ fallbackLocale: const Locale('en'),
+ useFallbackTranslations: true,
+ child: const MyApp(),
+ ),
+ );
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
- // This widget is the root of your application.
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- title: 'Flutter Demo',
- theme: ThemeData(
- // This is the theme of your application.
- //
- // Try running your application with "flutter run". You'll see the
- // application has a blue toolbar. Then, without quitting the app, try
- // changing the primarySwatch below to Colors.green and then invoke
- // "hot reload" (press "r" in the console where you ran "flutter run",
- // or simply save your changes to "hot reload" in a Flutter IDE).
- // Notice that the counter didn't reset back to zero; the application
- // is not restarted.
- primarySwatch: Colors.blue,
- ),
- home: const MyHomePage(title: 'Flutter Demo Home Page'),
- );
- }
-}
-
-class MyHomePage extends StatefulWidget {
- const MyHomePage({super.key, required this.title});
-
- // This widget is the home page of your application. It is stateful, meaning
- // that it has a State object (defined below) that contains fields that affect
- // how it looks.
-
- // This class is the configuration for the state. It holds the values (in this
- // case the title) provided by the parent (in this case the App widget) and
- // used by the build method of the State. Fields in a Widget subclass are
- // always marked "final".
-
- final String title;
-
- @override
- State createState() => _MyHomePageState();
-}
-
-class _MyHomePageState extends State {
- int _counter = 0;
-
- void _incrementCounter() {
- setState(() {
- // This call to setState tells the Flutter framework that something has
- // changed in this State, which causes it to rerun the build method below
- // so that the display can reflect the updated values. If we changed
- // _counter without calling setState(), then the build method would not be
- // called again, and so nothing would appear to happen.
- _counter++;
- });
- }
-
@override
Widget build(BuildContext context) {
- // This method is rerun every time setState is called, for instance as done
- // by the _incrementCounter method above.
- //
- // The Flutter framework has been optimized to make rerunning build methods
- // fast, so that you can just rebuild anything that needs updating rather
- // than having to individually change instances of widgets.
- return Scaffold(
- appBar: AppBar(
- // Here we take the value from the MyHomePage object that was created by
- // the App.build method, and use it to set our appbar title.
- title: Text(widget.title),
- ),
- body: Center(
- // Center is a layout widget. It takes a single child and positions it
- // in the middle of the parent.
- child: Column(
- // Column is also a layout widget. It takes a list of children and
- // arranges them vertically. By default, it sizes itself to fit its
- // children horizontally, and tries to be as tall as its parent.
- //
- // Invoke "debug painting" (press "p" in the console, choose the
- // "Toggle Debug Paint" action from the Flutter Inspector in Android
- // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
- // to see the wireframe for each widget.
- //
- // Column has various properties to control how it sizes itself and
- // how it positions its children. Here we use mainAxisAlignment to
- // center the children vertically; the main axis here is the vertical
- // axis because Columns are vertical (the cross axis would be
- // horizontal).
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- const Text(
- 'You have pushed the button this many times:',
- ),
- Text(
- '$_counter',
- style: Theme.of(context).textTheme.headlineMedium,
- ),
- ],
- ),
- ),
- floatingActionButton: FloatingActionButton(
- onPressed: _incrementCounter,
- tooltip: 'Increment',
- child: const Icon(Icons.add),
- ), // This trailing comma makes auto-formatting nicer for build methods.
+ final darkTheme = AppTheme.dark();
+ return MaterialApp.router(
+ localizationsDelegates: context.localizationDelegates,
+ supportedLocales: context.supportedLocales,
+ locale: context.locale,
+ debugShowCheckedModeBanner: false,
+ theme: darkTheme,
+ routerConfig: router,
);
}
}
diff --git a/lib/more/more.dart b/lib/more/more.dart
new file mode 100644
index 0000000..2bda9cd
--- /dev/null
+++ b/lib/more/more.dart
@@ -0,0 +1,10 @@
+import 'package:flutter/material.dart';
+
+class MoreScreen extends StatelessWidget {
+ const MoreScreen({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return const Center(child: Text("More"),);
+ }
+}
diff --git a/lib/moviedetails/movie_details.dart b/lib/moviedetails/movie_details.dart
new file mode 100644
index 0000000..06a6e53
--- /dev/null
+++ b/lib/moviedetails/movie_details.dart
@@ -0,0 +1,10 @@
+import 'package:flutter/material.dart';
+
+class MovieDetailsScreen extends StatelessWidget {
+ const MovieDetailsScreen({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return const Center(child: Text('Movie details'),);
+ }
+}
diff --git a/lib/onboarding/components/on_boarding_end_page.dart b/lib/onboarding/components/on_boarding_end_page.dart
new file mode 100644
index 0000000..e554b74
--- /dev/null
+++ b/lib/onboarding/components/on_boarding_end_page.dart
@@ -0,0 +1,112 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+import 'package:smooth_page_indicator/smooth_page_indicator.dart';
+
+import '../../generated/assets.gen.dart';
+import '../../generated/colors.gen.dart';
+import '../../generated/locale_keys.g.dart';
+
+class OnBoardingEndPage extends StatelessWidget {
+ const OnBoardingEndPage({
+ super.key,
+ required PageController controller,
+ required this.context,
+ }) : _controller = controller;
+
+ final PageController _controller;
+ final BuildContext context;
+
+ @override
+ Widget build(BuildContext context) {
+ return SizedBox.expand(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const SizedBox(
+ height: 132.0,
+ ),
+ IgnorePointer(
+ ignoring: true,
+ child: Image.asset(
+ Assets.images.marvelLogo.path,
+ width: 185.0,
+ height: 75.0,
+ fit: BoxFit.cover,
+ alignment: Alignment.center,
+ ),
+ ),
+ const SizedBox(
+ height: 60.0,
+ ),
+ IgnorePointer(
+ ignoring: true,
+ child: SmoothPageIndicator(
+ controller: _controller,
+ count: 6,
+ effect: const WormEffect(
+ activeDotColor: ColorName.crimsonApprox,
+ dotColor: Colors.white,
+ dotHeight: 10.0,
+ dotWidth: 10.0,
+ spacing: 10.0,
+ ),
+ ),
+ ),
+ const SizedBox(
+ height: 60.0,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(left: 50.0, right: 50.0),
+ child: SizedBox(
+ width: double.infinity,
+ height: 50.0,
+ child: TextButton(
+ style: TextButton.styleFrom(
+ backgroundColor: ColorName.crimsonApprox,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(Radius.zero),
+ ),
+ ),
+ onPressed: () {},
+ child: Text(
+ LocaleKeys.signup.tr(),
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(
+ height: 30.0,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(left: 50.0, right: 50.0),
+ child: SizedBox(
+ width: double.infinity,
+ height: 50.0,
+ child: TextButton(
+ style: TextButton.styleFrom(
+ backgroundColor: Colors.transparent,
+ side: const BorderSide(
+ width: 3.0,
+ color: ColorName.crimsonApprox,
+ ),
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(Radius.zero),
+ ),
+ ),
+ onPressed: () {
+ context.go(context.namedLocation('home'));
+ },
+ child: Text(
+ LocaleKeys.login.tr(),
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/onboarding/components/on_boarding_item_page.dart b/lib/onboarding/components/on_boarding_item_page.dart
new file mode 100644
index 0000000..5179f66
--- /dev/null
+++ b/lib/onboarding/components/on_boarding_item_page.dart
@@ -0,0 +1,99 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:smooth_page_indicator/smooth_page_indicator.dart';
+
+import '../../generated/assets.gen.dart';
+import '../../generated/colors.gen.dart';
+import '../../generated/locale_keys.g.dart';
+
+class OnBoardingItemPage extends StatelessWidget {
+ const OnBoardingItemPage({
+ super.key,
+ required PageController controller,
+ required String title,
+ required this.context,
+ }) : _controller = controller,
+ _title = title;
+
+ final PageController _controller;
+ final String _title;
+ final BuildContext context;
+
+ @override
+ Widget build(BuildContext context) {
+ return SizedBox.expand(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ IgnorePointer(
+ ignoring: true,
+ child: Image.asset(
+ Assets.images.marvelLogo.path,
+ width: 185.0,
+ height: 75.0,
+ fit: BoxFit.cover,
+ alignment: Alignment.center,
+ ),
+ ),
+ const SizedBox(height: 60.0),
+ IgnorePointer(
+ ignoring: true,
+ child: SmoothPageIndicator(
+ controller: _controller,
+ count: 6,
+ effect: const WormEffect(
+ activeDotColor: ColorName.crimsonApprox,
+ dotColor: Colors.white,
+ dotHeight: 10.0,
+ dotWidth: 10.0,
+ spacing: 10.0,
+ ),
+ ),
+ ),
+ const SizedBox(height: 40.0),
+ IgnorePointer(
+ ignoring: true,
+ child: SizedBox(
+ height: 115.0,
+ child: Text(
+ _title,
+ style: Theme.of(context).textTheme.titleLarge,
+ textAlign: TextAlign.center,
+ ),
+ ),
+ ),
+ const SizedBox(height: 53.0),
+ Padding(
+ padding: const EdgeInsets.only(
+ left: 50.0,
+ right: 50.0,
+ ),
+ child: SizedBox(
+ width: double.infinity,
+ height: 50.0,
+ child: TextButton(
+ style: TextButton.styleFrom(
+ backgroundColor: ColorName.crimsonApprox,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(Radius.zero),
+ ),
+ ),
+ onPressed: () {
+ _controller.nextPage(
+ duration: const Duration(milliseconds: 250),
+ curve: Curves.easeIn,
+ );
+ },
+ child: Text(
+ LocaleKeys.continueOnBoarding.tr(),
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(height: 40.0),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/onboarding/on_boarding.dart b/lib/onboarding/on_boarding.dart
new file mode 100644
index 0000000..8bbde5a
--- /dev/null
+++ b/lib/onboarding/on_boarding.dart
@@ -0,0 +1,93 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_movie_clean/generated/assets.gen.dart';
+import 'package:flutter_movie_clean/generated/locale_keys.g.dart';
+
+import 'components/on_boarding_end_page.dart';
+import 'components/on_boarding_item_page.dart';
+
+class OnBoardingScreen extends StatefulWidget {
+ const OnBoardingScreen({Key? key}) : super(key: key);
+
+ @override
+ State createState() => _OnBoardingScreenState();
+}
+
+class _OnBoardingScreenState extends State {
+ final PageController _controller = PageController();
+ bool _isEndPage = false;
+ final List _titles = [
+ LocaleKeys.onBoardingPageFirstTitle.tr(),
+ LocaleKeys.onBoardingPageSecondTitle.tr(),
+ LocaleKeys.onBoardingPageThirdTitle.tr(),
+ LocaleKeys.onBoardingPageFourthTitle.tr(),
+ LocaleKeys.onBoardingPageFifthTitle.tr(),
+ ];
+ String _title = '';
+ final List _posterPaths = [
+ Assets.images.onboardings.poster1.path,
+ Assets.images.onboardings.poster2.path,
+ Assets.images.onboardings.poster3.path,
+ Assets.images.onboardings.poster4.path,
+ Assets.images.onboardings.poster5.path,
+ Assets.images.onboardings.poster6.path,
+ ];
+
+ final Gradient _maskingGradient = const LinearGradient(
+ colors: [Colors.transparent, Colors.black],
+ stops: [0.0, 0.8],
+ begin: Alignment.topCenter,
+ end: Alignment.bottomCenter,
+ );
+
+ @override
+ void initState() {
+ super.initState();
+ _title = _titles.first;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Stack(
+ children: [
+ ShaderMask(
+ shaderCallback: (bounds) => _maskingGradient.createShader(bounds),
+ blendMode: BlendMode.darken,
+ child: PageView(
+ controller: _controller,
+ onPageChanged: (index) {
+ setState(() {
+ _isEndPage = index == _titles.length ? true : false;
+ _title = index < _titles.length ? _titles.elementAt(index) : '';
+ });
+ },
+ children: _posterPaths.map((path) => _posterItemPageView(path)).toList(),
+ ),
+ ),
+ _isEndPage
+ ? OnBoardingEndPage(controller: _controller, context: context)
+ : OnBoardingItemPage(controller: _controller, title: _title, context: context)
+ ],
+ ),
+ );
+ }
+
+ Widget _posterItemPageView(String poster) {
+ return Column(
+ children: [
+ Expanded(
+ child: Image.asset(
+ width: double.infinity,
+ poster,
+ fit: BoxFit.fill,
+ ),
+ ),
+ Container(
+ height: 150.0,
+ color: Colors.black,
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/router/router.dart b/lib/router/router.dart
new file mode 100644
index 0000000..63dd3f8
--- /dev/null
+++ b/lib/router/router.dart
@@ -0,0 +1,90 @@
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+
+import '../exports/screens.dart';
+import '../widgets/scaffold_with_nav_bar.dart';
+
+final GlobalKey _rootNavigatorKey = GlobalKey(debugLabel: 'root');
+final GlobalKey _shellNavigatorKey = GlobalKey(debugLabel: 'shell');
+const ValueKey _scaffoldKey = ValueKey('App scaffold');
+
+final GoRouter router = GoRouter(
+ navigatorKey: _rootNavigatorKey,
+ initialLocation: '/',
+ routes: [
+ GoRoute(
+ name: 'on_boarding',
+ path: '/',
+ builder: (BuildContext context, GoRouterState state) => const OnBoardingScreen(),
+ ),
+ ShellRoute(
+ navigatorKey: _shellNavigatorKey,
+ builder: (BuildContext context, GoRouterState state, Widget child) {
+ return ScaffoldWithNavBar(child: child);
+ },
+ routes: [
+ GoRoute(
+ name: 'home',
+ path: '/home',
+ pageBuilder: (BuildContext context, GoRouterState state) {
+ return FadeTransitionPage(
+ key: _scaffoldKey,
+ child: const HomeScreen(),
+ );
+ },
+ routes: [
+ GoRoute(
+ name: 'movie_details',
+ path: 'movie_details',
+ parentNavigatorKey: _rootNavigatorKey,
+ builder: (BuildContext context, GoRouterState state) => const MovieDetailsScreen(),
+ ),
+ ]),
+ GoRoute(
+ name: 'categories',
+ path: '/categories',
+ pageBuilder: (BuildContext context, GoRouterState state) {
+ return FadeTransitionPage(
+ key: _scaffoldKey,
+ child: const CategoriesScreen(),
+ );
+ }),
+ GoRoute(
+ name: 'downloads',
+ path: '/downloads',
+ pageBuilder: (BuildContext context, GoRouterState state) {
+ return FadeTransitionPage(
+ key: _scaffoldKey,
+ child: const DownloadsScreen(),
+ );
+ }),
+ GoRoute(
+ name: 'more',
+ path: '/more',
+ pageBuilder: (BuildContext context, GoRouterState state) {
+ return FadeTransitionPage(
+ key: _scaffoldKey,
+ child: const MoreScreen(),
+ );
+ }),
+ ],
+ ),
+ ],
+);
+
+class FadeTransitionPage extends CustomTransitionPage {
+ FadeTransitionPage({
+ required LocalKey super.key,
+ required super.child,
+ }) : super(transitionsBuilder: (
+ BuildContext context,
+ Animation animation,
+ Animation secondaryAnimation,
+ Widget child,
+ ) {
+ return FadeTransition(
+ opacity: animation.drive(CurveTween(curve: Curves.easeIn)),
+ child: child,
+ );
+ });
+}
diff --git a/lib/theme/app_theme.dart b/lib/theme/app_theme.dart
new file mode 100644
index 0000000..2bec9ef
--- /dev/null
+++ b/lib/theme/app_theme.dart
@@ -0,0 +1,53 @@
+import 'package:flutter/material.dart';
+
+class AppTheme {
+ static TextTheme lightTextTheme = const TextTheme(
+ titleLarge: TextStyle(
+ fontSize: 24.0,
+ fontWeight: FontWeight.w600,
+ color: Colors.black,
+ ),
+ titleMedium: TextStyle(
+ fontSize: 20.0,
+ fontWeight: FontWeight.w500,
+ color: Colors.black,
+ ),
+ titleSmall: TextStyle(
+ fontSize: 12.0,
+ fontWeight: FontWeight.w600,
+ color: Colors.black,
+ ),
+ );
+
+ static TextTheme dartTextTheme = const TextTheme(
+ titleLarge: TextStyle(
+ fontSize: 24.0,
+ fontWeight: FontWeight.w600,
+ color: Colors.white,
+ ),
+ titleMedium: TextStyle(
+ fontSize: 20.0,
+ fontWeight: FontWeight.w500,
+ color: Colors.white,
+ ),
+ titleSmall: TextStyle(
+ fontSize: 12.0,
+ fontWeight: FontWeight.w600,
+ color: Colors.white,
+ ),
+ );
+
+ static ThemeData light() {
+ return ThemeData(
+ brightness: Brightness.light,
+ textTheme: lightTextTheme,
+ );
+ }
+
+ static ThemeData dark() {
+ return ThemeData(
+ brightness: Brightness.dark,
+ textTheme: dartTextTheme,
+ );
+ }
+}
diff --git a/lib/widgets/header_widget.dart b/lib/widgets/header_widget.dart
new file mode 100644
index 0000000..795922f
--- /dev/null
+++ b/lib/widgets/header_widget.dart
@@ -0,0 +1,52 @@
+import 'package:flutter/material.dart';
+
+import '../generated/assets.gen.dart';
+
+class HeaderWidget extends StatelessWidget {
+ const HeaderWidget({Key? key, required this.onProfileTapped}) : super(key: key);
+
+ final Function() onProfileTapped;
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const Expanded(child: SizedBox()),
+ Expanded(
+ flex: 1,
+ child: Align(
+ alignment: Alignment.center,
+ child: Image.asset(
+ Assets.images.marvelLogo.path,
+ width: 100.0,
+ height: 45.26,
+ ),
+ ),
+ ),
+ Expanded(
+ flex: 1,
+ child: Align(
+ alignment: Alignment.centerRight,
+ child: Padding(
+ padding: const EdgeInsets.only(right: 16.0, top: 16.0, bottom: 16.0),
+ child: GestureDetector(
+ child: CircleAvatar(
+ radius: 35.0,
+ backgroundImage: AssetImage(Assets.images.bgProfile.path),
+ child: CircleAvatar(
+ radius: 27.0,
+ backgroundImage: AssetImage(Assets.images.profileAvatar.path),
+ ),
+ ),
+ onTap: () {
+ onProfileTapped();
+ },
+ ),
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/scaffold_with_nav_bar.dart b/lib/widgets/scaffold_with_nav_bar.dart
new file mode 100644
index 0000000..48bf5ef
--- /dev/null
+++ b/lib/widgets/scaffold_with_nav_bar.dart
@@ -0,0 +1,98 @@
+import 'dart:ui';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+
+import '../generated/assets.gen.dart';
+import '../generated/colors.gen.dart';
+import '../generated/locale_keys.g.dart';
+
+class ScaffoldWithNavBar extends StatelessWidget {
+ final Widget child;
+
+ const ScaffoldWithNavBar({required this.child, super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ extendBody: true,
+ body: child,
+ backgroundColor: Colors.black,
+ bottomNavigationBar: ClipRRect(
+ child: BackdropFilter(
+ filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
+ child: BottomNavigationBar(
+ items: [
+ BottomNavigationBarItem(
+ icon: Image.asset(Assets.images.icons.icHome.path),
+ activeIcon:
+ Image.asset(Assets.images.icons.icHome.path, color: ColorName.crimsonApprox),
+ label: LocaleKeys.home.tr(),
+ ),
+ BottomNavigationBarItem(
+ icon: Image.asset(Assets.images.icons.icCategories.path),
+ activeIcon: Image.asset(Assets.images.icons.icCategories.path,
+ color: ColorName.crimsonApprox),
+ label: LocaleKeys.categories.tr(),
+ ),
+ BottomNavigationBarItem(
+ icon: Image.asset(Assets.images.icons.icDownloads.path),
+ activeIcon: Image.asset(Assets.images.icons.icDownloads.path,
+ color: ColorName.crimsonApprox),
+ label: LocaleKeys.downloads.tr(),
+ ),
+ BottomNavigationBarItem(
+ icon: Image.asset(Assets.images.icons.icMore.path),
+ activeIcon:
+ Image.asset(Assets.images.icons.icMore.path, color: ColorName.crimsonApprox),
+ label: LocaleKeys.more.tr(),
+ )
+ ],
+ elevation: 0,
+ type: BottomNavigationBarType.fixed,
+ unselectedItemColor: Colors.white,
+ selectedItemColor: ColorName.crimsonApprox,
+ backgroundColor: Colors.black.withOpacity(0.7),
+ currentIndex: _calculateSelectedIndex(context),
+ onTap: (int index) => _onItemTapped(index, context),
+ ),
+ ),
+ ),
+ );
+ }
+
+ static int _calculateSelectedIndex(BuildContext context) {
+ final String location = GoRouterState.of(context).location;
+ if (location.startsWith('/home')) {
+ return 0;
+ }
+ if (location.startsWith('/categories')) {
+ return 1;
+ }
+ if (location.startsWith('/downloads')) {
+ return 2;
+ }
+ if (location.startsWith('/more')) {
+ return 3;
+ }
+ return 0;
+ }
+
+ _onItemTapped(int index, BuildContext context) {
+ switch (index) {
+ case 0:
+ GoRouter.of(context).go('/home');
+ break;
+ case 1:
+ GoRouter.of(context).go('/categories');
+ break;
+ case 2:
+ GoRouter.of(context).go('/downloads');
+ break;
+ case 3:
+ GoRouter.of(context).go('/more');
+ break;
+ }
+ }
+}
diff --git a/pubspec.lock b/pubspec.lock
index c317f07..0582a28 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1,6 +1,30 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
+ _fe_analyzer_shared:
+ dependency: transitive
+ description:
+ name: _fe_analyzer_shared
+ sha256: "98d1d33ed129b372846e862de23a0fc365745f4d7b5e786ce667fcbbb7ac5c07"
+ url: "https://pub.dev"
+ source: hosted
+ version: "55.0.0"
+ analyzer:
+ dependency: transitive
+ description:
+ name: analyzer
+ sha256: "881348aed9b0b425882c97732629a6a31093c8ff20fc4b3b03fb9d3d50a3a126"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.7.1"
+ args:
+ dependency: transitive
+ description:
+ name: args
+ sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
async:
dependency: transitive
description:
@@ -9,6 +33,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.10.0"
+ bloc:
+ dependency: transitive
+ description:
+ name: bloc
+ sha256: "658a5ae59edcf1e58aac98b000a71c762ad8f46f1394c34a52050cafb3e11a80"
+ url: "https://pub.dev"
+ source: hosted
+ version: "8.1.1"
boolean_selector:
dependency: transitive
description:
@@ -17,6 +49,78 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.1"
+ build:
+ dependency: transitive
+ description:
+ name: build
+ sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.1"
+ build_config:
+ dependency: transitive
+ description:
+ name: build_config
+ sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
+ build_daemon:
+ dependency: transitive
+ description:
+ name: build_daemon
+ sha256: "757153e5d9cd88253cb13f28c2fb55a537dc31fefd98137549895b5beb7c6169"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.1"
+ build_resolvers:
+ dependency: transitive
+ description:
+ name: build_resolvers
+ sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.0"
+ build_runner:
+ dependency: "direct dev"
+ description:
+ name: build_runner
+ sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.3"
+ build_runner_core:
+ dependency: transitive
+ description:
+ name: build_runner_core
+ sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292"
+ url: "https://pub.dev"
+ source: hosted
+ version: "7.2.7"
+ built_collection:
+ dependency: transitive
+ description:
+ name: built_collection
+ sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.1.1"
+ built_value:
+ dependency: transitive
+ description:
+ name: built_value
+ sha256: "31b7c748fd4b9adf8d25d72a4c4a59ef119f12876cf414f94f8af5131d5fa2b0"
+ url: "https://pub.dev"
+ source: hosted
+ version: "8.4.4"
+ carousel_slider:
+ dependency: "direct main"
+ description:
+ name: carousel_slider
+ sha256: "9c695cc963bf1d04a47bd6021f68befce8970bcd61d24938e1fb0918cf5d9c42"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.2.1"
characters:
dependency: transitive
description:
@@ -25,6 +129,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.1"
+ checked_yaml:
+ dependency: transitive
+ description:
+ name: checked_yaml
+ sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.2"
clock:
dependency: transitive
description:
@@ -33,6 +145,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
+ code_builder:
+ dependency: transitive
+ description:
+ name: code_builder
+ sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.4.0"
collection:
dependency: transitive
description:
@@ -41,6 +161,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.17.0"
+ color:
+ dependency: transitive
+ description:
+ name: color
+ sha256: ddcdf1b3badd7008233f5acffaf20ca9f5dc2cd0172b75f68f24526a5f5725cb
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.0"
+ convert:
+ dependency: transitive
+ description:
+ name: convert
+ sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.1"
+ crypto:
+ dependency: transitive
+ description:
+ name: crypto
+ sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.2"
cupertino_icons:
dependency: "direct main"
description:
@@ -49,6 +193,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.5"
+ dart_style:
+ dependency: transitive
+ description:
+ name: dart_style
+ sha256: "6d691edde054969f0e0f26abb1b30834b5138b963793e56f69d3a9a4435e6352"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.0"
+ dartx:
+ dependency: transitive
+ description:
+ name: dartx
+ sha256: "45d7176701f16c5a5e00a4798791c1964bc231491b879369c818dd9a9c764871"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.0"
data:
dependency: "direct main"
description:
@@ -63,6 +223,22 @@ packages:
relative: true
source: path
version: "0.0.1"
+ easy_localization:
+ dependency: "direct main"
+ description:
+ name: easy_localization
+ sha256: "6a2e99fa0bfe5765bf4c6ca9b137d5de2c75593007178c5e4cd2ae985f870080"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.1"
+ easy_logger:
+ dependency: transitive
+ description:
+ name: easy_logger
+ sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.0.2"
fake_async:
dependency: transitive
description:
@@ -71,11 +247,59 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.1"
+ ffi:
+ dependency: transitive
+ description:
+ name: ffi
+ sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.1"
+ file:
+ dependency: transitive
+ description:
+ name: file
+ sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.1.4"
+ fixnum:
+ dependency: transitive
+ description:
+ name: fixnum
+ sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.0"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
+ flutter_bloc:
+ dependency: "direct main"
+ description:
+ name: flutter_bloc
+ sha256: "434951eea948dbe87f737b674281465f610b8259c16c097b8163ce138749a775"
+ url: "https://pub.dev"
+ source: hosted
+ version: "8.1.2"
+ flutter_gen_core:
+ dependency: transitive
+ description:
+ name: flutter_gen_core
+ sha256: e74db9fc706ce43ef0dfd4b296fcfa10f84c4d862b9b68a087e7c703f97c7a0a
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.2.0"
+ flutter_gen_runner:
+ dependency: "direct dev"
+ description:
+ name: flutter_gen_runner
+ sha256: "434511d7c3f7bb5c67d89a16451056093953bebf7afa8336baeceddfc6fe2a21"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.2.0"
flutter_lints:
dependency: "direct dev"
description:
@@ -84,11 +308,85 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.1"
+ flutter_localizations:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
+ flutter_web_plugins:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ frontend_server_client:
+ dependency: transitive
+ description:
+ name: frontend_server_client
+ sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.0"
+ glob:
+ dependency: transitive
+ description:
+ name: glob
+ sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.1"
+ go_router:
+ dependency: "direct main"
+ description:
+ name: go_router
+ sha256: "871f6f89426ab20286d4e8aaa0f85b6fe91607e1720375f1baecbd34602df409"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.3.0"
+ graphs:
+ dependency: transitive
+ description:
+ name: graphs
+ sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.0"
+ http_multi_server:
+ dependency: transitive
+ description:
+ name: http_multi_server
+ sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.1"
+ http_parser:
+ dependency: transitive
+ description:
+ name: http_parser
+ sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.2"
+ intl:
+ dependency: transitive
+ description:
+ name: intl
+ sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.17.0"
+ io:
+ dependency: transitive
+ description:
+ name: io
+ sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
js:
dependency: transitive
description:
@@ -97,6 +395,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.6.5"
+ json_annotation:
+ dependency: transitive
+ description:
+ name: json_annotation
+ sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.8.0"
lints:
dependency: transitive
description:
@@ -105,6 +411,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.1"
+ logging:
+ dependency: transitive
+ description:
+ name: logging
+ sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
matcher:
dependency: transitive
description:
@@ -129,6 +443,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.8.0"
+ mime:
+ dependency: transitive
+ description:
+ name: mime
+ sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
+ nested:
+ dependency: transitive
+ description:
+ name: nested
+ sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.0"
+ package_config:
+ dependency: transitive
+ description:
+ name: package_config
+ sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.0"
path:
dependency: transitive
description:
@@ -137,11 +475,179 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.8.2"
+ path_provider_linux:
+ dependency: transitive
+ description:
+ name: path_provider_linux
+ sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.10"
+ path_provider_platform_interface:
+ dependency: transitive
+ description:
+ name: path_provider_platform_interface
+ sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.6"
+ path_provider_windows:
+ dependency: transitive
+ description:
+ name: path_provider_windows
+ sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.5"
+ petitparser:
+ dependency: transitive
+ description:
+ name: petitparser
+ sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.1.0"
+ platform:
+ dependency: transitive
+ description:
+ name: platform
+ sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.0"
+ plugin_platform_interface:
+ dependency: transitive
+ description:
+ name: plugin_platform_interface
+ sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
+ pool:
+ dependency: transitive
+ description:
+ name: pool
+ sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.5.1"
+ process:
+ dependency: transitive
+ description:
+ name: process
+ sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.2.4"
+ provider:
+ dependency: transitive
+ description:
+ name: provider
+ sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.0.5"
+ pub_semver:
+ dependency: transitive
+ description:
+ name: pub_semver
+ sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.3"
+ pubspec_parse:
+ dependency: transitive
+ description:
+ name: pubspec_parse
+ sha256: ec85d7d55339d85f44ec2b682a82fea340071e8978257e5a43e69f79e98ef50c
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.2"
+ shared_preferences:
+ dependency: transitive
+ description:
+ name: shared_preferences
+ sha256: ee6257848f822b8481691f20c3e6d2bfee2e9eccb2a3d249907fcfb198c55b41
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.18"
+ shared_preferences_android:
+ dependency: transitive
+ description:
+ name: shared_preferences_android
+ sha256: ad423a80fe7b4e48b50d6111b3ea1027af0e959e49d485712e134863d9c1c521
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.17"
+ shared_preferences_foundation:
+ dependency: transitive
+ description:
+ name: shared_preferences_foundation
+ sha256: "1e755f8583229f185cfca61b1d80fb2344c9d660e1c69ede5450d8f478fa5310"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.5"
+ shared_preferences_linux:
+ dependency: transitive
+ description:
+ name: shared_preferences_linux
+ sha256: "3a59ed10890a8409ad0faad7bb2957dab4b92b8fbe553257b05d30ed8af2c707"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.5"
+ shared_preferences_platform_interface:
+ dependency: transitive
+ description:
+ name: shared_preferences_platform_interface
+ sha256: "824bfd02713e37603b2bdade0842e47d56e7db32b1dcdd1cae533fb88e2913fc"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.1"
+ shared_preferences_web:
+ dependency: transitive
+ description:
+ name: shared_preferences_web
+ sha256: "0dc2633f215a3d4aa3184c9b2c5766f4711e4e5a6b256e62aafee41f89f1bfb8"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.6"
+ shared_preferences_windows:
+ dependency: transitive
+ description:
+ name: shared_preferences_windows
+ sha256: "71bcd669bb9cdb6b39f22c4a7728b6d49e934f6cba73157ffa5a54f1eed67436"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.5"
+ shelf:
+ dependency: transitive
+ description:
+ name: shelf
+ sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.0"
+ shelf_web_socket:
+ dependency: transitive
+ description:
+ name: shelf_web_socket
+ sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.3"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
+ smooth_page_indicator:
+ dependency: "direct main"
+ description:
+ name: smooth_page_indicator
+ sha256: "8c301bc686892306cd41672c1880167f140c16be305d5ede8201fefd9fcda829"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
source_span:
dependency: transitive
description:
@@ -166,6 +672,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.1"
+ stream_transform:
+ dependency: transitive
+ description:
+ name: stream_transform
+ sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.0"
string_scanner:
dependency: transitive
description:
@@ -190,6 +704,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.4.16"
+ time:
+ dependency: transitive
+ description:
+ name: time
+ sha256: "83427e11d9072e038364a5e4da559e85869b227cf699a541be0da74f14140124"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.3"
+ timing:
+ dependency: transitive
+ description:
+ name: timing
+ sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
+ typed_data:
+ dependency: transitive
+ description:
+ name: typed_data
+ sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.1"
vector_math:
dependency: transitive
description:
@@ -198,6 +736,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
+ watcher:
+ dependency: transitive
+ description:
+ name: watcher
+ sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.2"
+ web_socket_channel:
+ dependency: transitive
+ description:
+ name: web_socket_channel
+ sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.0"
+ win32:
+ dependency: transitive
+ description:
+ name: win32
+ sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.3"
+ xdg_directories:
+ dependency: transitive
+ description:
+ name: xdg_directories
+ sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.0"
+ xml:
+ dependency: transitive
+ description:
+ name: xml
+ sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.2.2"
+ yaml:
+ dependency: transitive
+ description:
+ name: yaml
+ sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.1"
sdks:
dart: ">=2.19.4 <3.0.0"
- flutter: ">=1.17.0"
+ flutter: ">=3.3.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 7317433..c4f1122 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -38,8 +38,15 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.5
+ easy_localization: ^3.0.1
+ smooth_page_indicator: ^1.0.1
+ flutter_bloc: ^8.1.2
+ go_router: ^6.3.0
+ carousel_slider: ^4.2.1
dev_dependencies:
+ build_runner:
+ flutter_gen_runner:
flutter_test:
sdk: flutter
@@ -50,11 +57,27 @@ dev_dependencies:
# rules and activating additional ones.
flutter_lints: ^2.0.1
+flutter_gen:
+ output: lib/generated # Optional (default: lib/gen/)
+ line_length: 160 # Optional (default: 80)
+ null_safety: true
+
+ colors:
+ inputs:
+ - assets/color/colors.xml
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
+ assets:
+ - assets/images/
+ - assets/images/icons/
+ - assets/images/onboardings/
+ - assets/images/movies/
+ - assets/images/series/
+ - assets/images/trendings/
+ - assets/translations/
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
diff --git a/test/widget_test.dart b/test/widget_test.dart
index 60e5acb..84aae55 100644
--- a/test/widget_test.dart
+++ b/test/widget_test.dart
@@ -13,7 +13,7 @@ import 'package:flutter_movie_clean/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
- await tester.pumpWidget(const MyApp());
+ await tester.pumpWidget(MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);