From 618f5d135bded6b029212b280f32c0e06f0135d0 Mon Sep 17 00:00:00 2001 From: daniel-michel <65034538+daniel-michel@users.noreply.github.com> Date: Mon, 8 Jan 2024 12:57:36 +0100 Subject: [PATCH] feature: add bookmarking functionality --- lib/main.dart | 28 ++++++++++++++++++++++++---- lib/model/movie.dart | 23 ++++++++++++++++++----- lib/model/movie_manager.dart | 2 +- lib/view/movie_item.dart | 13 ++++++++++--- lib/view/movie_list.dart | 20 +++++++++++++++++++- lib/view/movie_manager_list.dart | 6 ++++-- test/model/movie_test.dart | 2 +- 7 files changed, 77 insertions(+), 17 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 982aabd..866ea6d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -43,10 +43,30 @@ class HomePage extends StatelessWidget { child: const Icon(Icons.delete)) ], ), - body: MovieManagerList(manager), - floatingActionButton: FloatingActionButton( - child: const Icon(Icons.refresh), - onPressed: () => manager.loadUpcomingMovies(), + body: DefaultTabController( + length: 2, + child: Column( + children: [ + Expanded( + child: TabBarView( + children: [ + Scaffold( + body: MovieManagerList(manager), + floatingActionButton: FloatingActionButton( + child: const Icon(Icons.refresh), + onPressed: () => manager.loadUpcomingMovies(), + ), + ), + MovieManagerList(manager, filter: (movie) => movie.bookmarked) + ], + ), + ), + const TabBar(tabs: [ + Tab(icon: Icon(Icons.list), child: Text("Upcoming")), + Tab(icon: Icon(Icons.bookmark), child: Text("Bookmarked")), + ]), + ], + ), ), ); } diff --git a/lib/model/movie.dart b/lib/model/movie.dart index 7f6db88..f162247 100644 --- a/lib/model/movie.dart +++ b/lib/model/movie.dart @@ -4,6 +4,7 @@ import 'package:intl/intl.dart'; class MovieData extends ChangeNotifier { String _title; DateWithPrecisionAndCountry _releaseDate; + bool _bookmarked = false; bool _hasDetails = false; List? _releaseDates; @@ -21,6 +22,10 @@ class MovieData extends ChangeNotifier { return _releaseDate; } + bool get bookmarked { + return _bookmarked; + } + List? get releaseDates { return _releaseDates; } @@ -41,7 +46,9 @@ class MovieData extends ChangeNotifier { return _hasDetails; } - void updateWithNew(MovieData movie) { + /// Updates the information with that of a new version of the movie + /// but ignores fields that are user controlled, like whether the movie was bookmarked. + void updateWithNewIgnoringUserControlled(MovieData movie) { setDetails( title: movie.title, releaseDate: movie.releaseDate, @@ -54,6 +61,7 @@ class MovieData extends ChangeNotifier { void setDetails( {String? title, DateWithPrecisionAndCountry? releaseDate, + bool? bookmarked, List? releaseDates, List? genres, List? titles, @@ -64,6 +72,9 @@ class MovieData extends ChangeNotifier { if (releaseDate != null) { _releaseDate = releaseDate; } + if (bookmarked != null) { + _bookmarked = bookmarked; + } if (releaseDates != null) { _releaseDates = releaseDates; } @@ -85,6 +96,10 @@ class MovieData extends ChangeNotifier { return "$title (${_releaseDate.toString()}${_genres?.isNotEmpty ?? true ? "; ${_genres?.join(", ")}" : ""})"; } + bool same(MovieData other) { + return title == other.title && releaseDate.date == other.releaseDate.date; + } + Map toJsonEncodable() { List? releaseDatesByCountry = _releaseDates?.map((e) => e.toJsonEncodable()).toList(); @@ -92,6 +107,7 @@ class MovieData extends ChangeNotifier { return { "title": title, "releaseDate": _releaseDate.toJsonEncodable(), + "bookmarked": _bookmarked, "releaseDates": releaseDatesByCountry, "genres": genres, "titles": titlesByCountry, @@ -99,15 +115,12 @@ class MovieData extends ChangeNotifier { }; } - bool same(MovieData other) { - return title == other.title && releaseDate.date == other.releaseDate.date; - } - MovieData.fromJsonEncodable(Map json) : _title = json["title"], _releaseDate = DateWithPrecisionAndCountry.fromJsonEncodable(json["releaseDate"]) { setDetails( + bookmarked: json["bookmarked"] as bool, genres: (json["genres"] as List?) ?.map((genre) => genre as String) .toList(), diff --git a/lib/model/movie_manager.dart b/lib/model/movie_manager.dart index 874ff10..2b939e0 100644 --- a/lib/model/movie_manager.dart +++ b/lib/model/movie_manager.dart @@ -54,7 +54,7 @@ class MovieManager extends ChangeNotifier { added = true; actualMovies.add(movie); } else { - existing.updateWithNew(movie); + existing.updateWithNewIgnoringUserControlled(movie); actualMovies.add(existing); } } diff --git a/lib/view/movie_item.dart b/lib/view/movie_item.dart index bbef14b..35c68c9 100644 --- a/lib/view/movie_item.dart +++ b/lib/view/movie_item.dart @@ -12,9 +12,16 @@ class MovieItem extends StatelessWidget { animation: movie, builder: (context, widget) { return ListTile( - title: Text(movie.title), - subtitle: Text( - "${dateRelativeToNow(movie.releaseDate.date)}, ${movie.releaseDate.toString()}, ${movie.genres?.join(", ") ?? ""}")); + title: Text(movie.title), + subtitle: Text( + "${dateRelativeToNow(movie.releaseDate.date)}, ${movie.releaseDate.toString()}, ${movie.genres?.join(", ") ?? ""}"), + trailing: TextButton( + child: Icon(movie.bookmarked + ? Icons.bookmark_added + : Icons.bookmark_border), + onPressed: () => movie.setDetails(bookmarked: !movie.bookmarked), + ), + ); }, ); } diff --git a/lib/view/movie_list.dart b/lib/view/movie_list.dart index 2b428c9..0d43f9b 100644 --- a/lib/view/movie_list.dart +++ b/lib/view/movie_list.dart @@ -4,10 +4,28 @@ import 'package:release_schedule/view/movie_item.dart'; class MovieList extends StatelessWidget { final List movies; - const MovieList(this.movies, {super.key}); + final bool Function(MovieData)? filter; + const MovieList(this.movies, {this.filter, super.key}); @override Widget build(Object context) { + final localFilter = filter; + if (localFilter != null) { + List indexMap = []; + int index = 0; + for (var movie in movies) { + if (localFilter(movie)) { + indexMap.add(index); + } + index++; + } + return ListView.builder( + itemCount: indexMap.length, + itemBuilder: (context, index) { + return MovieItem(movies[indexMap[index]]); + }, + ); + } return ListView.builder( itemCount: movies.length, itemBuilder: (context, index) { diff --git a/lib/view/movie_manager_list.dart b/lib/view/movie_manager_list.dart index fae20ee..10dc0ab 100644 --- a/lib/view/movie_manager_list.dart +++ b/lib/view/movie_manager_list.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:release_schedule/model/movie.dart'; import 'package:release_schedule/model/movie_manager.dart'; import 'package:release_schedule/view/movie_list.dart'; class MovieManagerList extends StatelessWidget { final MovieManager manager; - const MovieManagerList(this.manager, {super.key}); + final bool Function(MovieData)? filter; + const MovieManagerList(this.manager, {this.filter, super.key}); @override Widget build(BuildContext context) { @@ -14,7 +16,7 @@ class MovieManagerList extends StatelessWidget { return Column( children: [ manager.loading ? const LinearProgressIndicator() : Container(), - Expanded(child: MovieList(manager.movies)) + Expanded(child: MovieList(manager.movies, filter: filter)) ], ); }, diff --git a/test/model/movie_test.dart b/test/model/movie_test.dart index 8c3b380..9e90147 100644 --- a/test/model/movie_test.dart +++ b/test/model/movie_test.dart @@ -23,7 +23,7 @@ void main() { ], reviews: [ Review('8.5', 'John Doe', DateTime(2023, 1, 1), 100) ]); - movie1.updateWithNew(movie2); + movie1.updateWithNewIgnoringUserControlled(movie2); expect(movie1.title, equals('Title 2')); expect(movie1.releaseDate.country, equals('UK')); expect(movie1.releaseDates!.length, equals(1));