Skip to content

Commit c956aeb

Browse files
committed
- Implement universal search for movies and TV series
- Refactor TV series detail page UI - Update TV series card and list pages - Add TV series duration formatting
1 parent 67e43e9 commit c956aeb

18 files changed

+715
-278
lines changed

lib/core/utils/utils.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,14 @@ String formatDuration(int minutes) {
22
final hours = minutes ~/ 60;
33
final remainingMinutes = minutes % 60;
44
return '${hours}h ${remainingMinutes}m';
5+
}
6+
7+
String formatTvDuration(List<int>? episodeRunTime) {
8+
if (episodeRunTime == null || episodeRunTime.isEmpty) {
9+
return 'N/A';
10+
}
11+
12+
// For TV series, we'll show the average episode runtime
13+
final avgRuntime = episodeRunTime.reduce((a, b) => a + b) ~/ episodeRunTime.length;
14+
return '${avgRuntime}m';
515
}

lib/features/movie/presentation/pages/movie_main_page.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ class _MovieMainPageState extends ConsumerState<MovieMainPage> {
3232
@override
3333
Widget build(BuildContext context) {
3434
return Scaffold(
35-
appBar: AppBar(
36-
title: const Text(''),
37-
automaticallyImplyLeading: false,
38-
),
3935
body: _pages[_selectedIndex],
4036
bottomNavigationBar: BottomNavigationBar(
4137
currentIndex: _selectedIndex,

lib/features/movie/presentation/pages/now_playing_page.dart

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -54,34 +54,32 @@ class _MovieHomePageState extends ConsumerState<NowPlayingPage> {
5454

5555
@override
5656
Widget build(BuildContext context) {
57-
return Scaffold(
58-
body: _isInitialLoading
59-
? const Center(child: CircularProgressIndicator())
60-
: Column(
61-
children: [
62-
Expanded(
63-
child: GridView.builder(
64-
controller: _scrollController,
65-
padding: const EdgeInsets.all(8),
66-
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
67-
crossAxisCount: 2,
68-
childAspectRatio: 2 / 3,
69-
crossAxisSpacing: 8,
70-
mainAxisSpacing: 8,
71-
),
72-
itemCount: _movies.length,
73-
itemBuilder: (context, index) {
74-
return MovieCardWidget(movie: _movies[index]);
75-
},
57+
return _isInitialLoading
58+
? const Center(child: CircularProgressIndicator())
59+
: Column(
60+
children: [
61+
Expanded(
62+
child: GridView.builder(
63+
controller: _scrollController,
64+
padding: const EdgeInsets.all(8),
65+
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
66+
crossAxisCount: 2,
67+
childAspectRatio: 2 / 3,
68+
crossAxisSpacing: 8,
69+
mainAxisSpacing: 8,
7670
),
71+
itemCount: _movies.length,
72+
itemBuilder: (context, index) {
73+
return MovieCardWidget(movie: _movies[index]);
74+
},
7775
),
78-
if (_hasMore && _isLoadingMore && !_isInitialLoading)
79-
const Padding(
80-
padding: EdgeInsets.only(bottom: 24.0, top: 8.0),
81-
child: CircularProgressIndicator(),
82-
),
83-
],
84-
),
76+
),
77+
if (_hasMore && _isLoadingMore && !_isInitialLoading)
78+
const Padding(
79+
padding: EdgeInsets.only(bottom: 24.0, top: 8.0),
80+
child: CircularProgressIndicator(),
81+
),
82+
],
8583
);
8684
}
8785
}

lib/features/movie/presentation/pages/popular_page.dart

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -54,34 +54,32 @@ class _PopularMoviePageState extends ConsumerState<PopularPage> {
5454

5555
@override
5656
Widget build(BuildContext context) {
57-
return Scaffold(
58-
body: _isInitialLoading
59-
? const Center(child: CircularProgressIndicator())
60-
: Column(
61-
children: [
62-
Expanded(
63-
child: GridView.builder(
64-
controller: _scrollController,
65-
padding: const EdgeInsets.all(8),
66-
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
67-
crossAxisCount: 2,
68-
childAspectRatio: 2 / 3,
69-
crossAxisSpacing: 8,
70-
mainAxisSpacing: 8,
71-
),
72-
itemCount: _movies.length,
73-
itemBuilder: (context, index) {
74-
return MovieCardWidget(movie: _movies[index]);
75-
},
57+
return _isInitialLoading
58+
? const Center(child: CircularProgressIndicator())
59+
: Column(
60+
children: [
61+
Expanded(
62+
child: GridView.builder(
63+
controller: _scrollController,
64+
padding: const EdgeInsets.all(8),
65+
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
66+
crossAxisCount: 2,
67+
childAspectRatio: 2 / 3,
68+
crossAxisSpacing: 8,
69+
mainAxisSpacing: 8,
7670
),
71+
itemCount: _movies.length,
72+
itemBuilder: (context, index) {
73+
return MovieCardWidget(movie: _movies[index]);
74+
},
7775
),
78-
if (_hasMore && _isLoadingMore && !_isInitialLoading)
79-
const Padding(
80-
padding: EdgeInsets.only(bottom: 24.0, top: 8.0),
81-
child: CircularProgressIndicator(),
82-
),
83-
],
84-
),
76+
),
77+
if (_hasMore && _isLoadingMore && !_isInitialLoading)
78+
const Padding(
79+
padding: EdgeInsets.only(bottom: 24.0, top: 8.0),
80+
child: CircularProgressIndicator(),
81+
),
82+
],
8583
);
8684
}
8785
}

lib/features/movie/presentation/pages/top_rated_page.dart

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -54,34 +54,32 @@ class _TopRatedMoviePageState extends ConsumerState<TopRatedPage> {
5454

5555
@override
5656
Widget build(BuildContext context) {
57-
return Scaffold(
58-
body: _isInitialLoading
59-
? const Center(child: CircularProgressIndicator())
60-
: Column(
61-
children: [
62-
Expanded(
63-
child: GridView.builder(
64-
controller: _scrollController,
65-
padding: const EdgeInsets.all(8),
66-
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
67-
crossAxisCount: 2,
68-
childAspectRatio: 2 / 3,
69-
crossAxisSpacing: 8,
70-
mainAxisSpacing: 8,
71-
),
72-
itemCount: _movies.length,
73-
itemBuilder: (context, index) {
74-
return MovieCardWidget(movie: _movies[index]);
75-
},
57+
return _isInitialLoading
58+
? const Center(child: CircularProgressIndicator())
59+
: Column(
60+
children: [
61+
Expanded(
62+
child: GridView.builder(
63+
controller: _scrollController,
64+
padding: const EdgeInsets.all(8),
65+
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
66+
crossAxisCount: 2,
67+
childAspectRatio: 2 / 3,
68+
crossAxisSpacing: 8,
69+
mainAxisSpacing: 8,
7670
),
71+
itemCount: _movies.length,
72+
itemBuilder: (context, index) {
73+
return MovieCardWidget(movie: _movies[index]);
74+
},
7775
),
78-
if (_hasMore && _isLoadingMore && !_isInitialLoading)
79-
const Padding(
80-
padding: EdgeInsets.only(bottom: 24.0, top: 8.0),
81-
child: CircularProgressIndicator(),
82-
),
83-
],
84-
),
76+
),
77+
if (_hasMore && _isLoadingMore && !_isInitialLoading)
78+
const Padding(
79+
padding: EdgeInsets.only(bottom: 24.0, top: 8.0),
80+
child: CircularProgressIndicator(),
81+
),
82+
],
8583
);
8684
}
8785
}

lib/features/movie/presentation/pages/up_coming_page.dart

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -54,34 +54,32 @@ class _UpComingMoviePageState extends ConsumerState<UpComingPage> {
5454

5555
@override
5656
Widget build(BuildContext context) {
57-
return Scaffold(
58-
body: _isInitialLoading
59-
? const Center(child: CircularProgressIndicator())
60-
: Column(
61-
children: [
62-
Expanded(
63-
child: GridView.builder(
64-
controller: _scrollController,
65-
padding: const EdgeInsets.all(8),
66-
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
67-
crossAxisCount: 2,
68-
childAspectRatio: 2 / 3,
69-
crossAxisSpacing: 8,
70-
mainAxisSpacing: 8,
71-
),
72-
itemCount: _movies.length,
73-
itemBuilder: (context, index) {
74-
return MovieCardWidget(movie: _movies[index]);
75-
},
57+
return _isInitialLoading
58+
? const Center(child: CircularProgressIndicator())
59+
: Column(
60+
children: [
61+
Expanded(
62+
child: GridView.builder(
63+
controller: _scrollController,
64+
padding: const EdgeInsets.all(8),
65+
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
66+
crossAxisCount: 2,
67+
childAspectRatio: 2 / 3,
68+
crossAxisSpacing: 8,
69+
mainAxisSpacing: 8,
7670
),
71+
itemCount: _movies.length,
72+
itemBuilder: (context, index) {
73+
return MovieCardWidget(movie: _movies[index]);
74+
},
7775
),
78-
if (_hasMore && _isLoadingMore && !_isInitialLoading)
79-
const Padding(
80-
padding: EdgeInsets.only(bottom: 24.0, top: 8.0),
81-
child: CircularProgressIndicator(),
82-
),
83-
],
84-
),
76+
),
77+
if (_hasMore && _isLoadingMore && !_isInitialLoading)
78+
const Padding(
79+
padding: EdgeInsets.only(bottom: 24.0, top: 8.0),
80+
child: CircularProgressIndicator(),
81+
),
82+
],
8583
);
8684
}
8785
}

lib/features/tv_series/data/models/tv_series_detail_model.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ class TvSeriesDetailModel with _$TvSeriesDetailModel {
1313
required String overview,
1414
@JsonKey(name: 'first_air_date') required String firstAirDate,
1515
@JsonKey(name: 'vote_average') required double voteAverage,
16+
@JsonKey(name: 'original_language') String? originalLanguage,
17+
@JsonKey(name: 'episode_run_time') List<int>? episodeRunTime,
18+
@JsonKey(name: 'last_air_date') String? lastAirDate,
19+
@JsonKey(name: 'number_of_episodes') int? numberOfEpisodes,
20+
@JsonKey(name: 'number_of_seasons') int? numberOfSeasons,
1621
}) = _TvSeriesDetailModel;
1722

1823
factory TvSeriesDetailModel.fromJson(Map<String, dynamic> json) =>

lib/features/tv_series/data/repositories/tv_series_repository_impl.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ class TvSeriesRepositoryImpl implements TvSeriesRepository {
7272
overview: model.overview,
7373
voteAverage: model.voteAverage,
7474
firstAirDate: model.firstAirDate,
75+
originalLanguage: model.originalLanguage,
76+
episodeRunTime: model.episodeRunTime,
77+
lastAirDate: model.lastAirDate,
78+
numberOfEpisodes: model.numberOfEpisodes,
79+
numberOfSeasons: model.numberOfSeasons,
7580
);
7681
}
7782

lib/features/tv_series/domain/entities/tv_series_detail.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ class TvSeriesDetail {
55
final String overview;
66
final double voteAverage;
77
final String firstAirDate;
8+
final String? originalLanguage;
9+
final List<int>? episodeRunTime;
10+
final String? lastAirDate;
11+
final int? numberOfEpisodes;
12+
final int? numberOfSeasons;
813

914
TvSeriesDetail({
1015
required this.id,
@@ -13,5 +18,10 @@ class TvSeriesDetail {
1318
required this.overview,
1419
required this.voteAverage,
1520
required this.firstAirDate,
21+
this.originalLanguage,
22+
this.episodeRunTime,
23+
this.lastAirDate,
24+
this.numberOfEpisodes,
25+
this.numberOfSeasons,
1626
});
1727
}

lib/features/tv_series/presentation/pages/airing_today_page.dart

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -54,34 +54,32 @@ class _AiringTodayPageState extends ConsumerState<AiringTodayPage> {
5454

5555
@override
5656
Widget build(BuildContext context) {
57-
return Scaffold(
58-
body: _isInitialLoading
59-
? const Center(child: CircularProgressIndicator())
60-
: Column(
61-
children: [
62-
Expanded(
63-
child: GridView.builder(
64-
controller: _scrollController,
65-
padding: const EdgeInsets.all(8),
66-
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
67-
crossAxisCount: 2,
68-
childAspectRatio: 2 / 3,
69-
crossAxisSpacing: 8,
70-
mainAxisSpacing: 8,
71-
),
72-
itemCount: _tvSeries.length,
73-
itemBuilder: (context, index) {
74-
return TvSeriesCardWidget(tvSeries: _tvSeries[index]);
75-
},
57+
return _isInitialLoading
58+
? const Center(child: CircularProgressIndicator())
59+
: Column(
60+
children: [
61+
Expanded(
62+
child: GridView.builder(
63+
controller: _scrollController,
64+
padding: const EdgeInsets.all(8),
65+
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
66+
crossAxisCount: 2,
67+
childAspectRatio: 2 / 3,
68+
crossAxisSpacing: 8,
69+
mainAxisSpacing: 8,
7670
),
71+
itemCount: _tvSeries.length,
72+
itemBuilder: (context, index) {
73+
return TvSeriesCardWidget(tvSeries: _tvSeries[index]);
74+
},
7775
),
78-
if (_hasMore && _isLoadingMore && !_isInitialLoading)
79-
const Padding(
80-
padding: EdgeInsets.only(bottom: 24.0, top: 8.0),
81-
child: CircularProgressIndicator(),
82-
),
83-
],
84-
),
85-
);
76+
),
77+
if (_hasMore && _isLoadingMore && !_isInitialLoading)
78+
const Padding(
79+
padding: EdgeInsets.only(bottom: 24.0, top: 8.0),
80+
child: CircularProgressIndicator(),
81+
),
82+
],
83+
);
8684
}
8785
}

0 commit comments

Comments
 (0)