feature: add bookmarking functionality
parent
688fa63da2
commit
618f5d135b
|
@ -43,11 +43,31 @@ class HomePage extends StatelessWidget {
|
|||
child: const Icon(Icons.delete))
|
||||
],
|
||||
),
|
||||
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")),
|
||||
]),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:intl/intl.dart';
|
|||
class MovieData extends ChangeNotifier {
|
||||
String _title;
|
||||
DateWithPrecisionAndCountry _releaseDate;
|
||||
bool _bookmarked = false;
|
||||
|
||||
bool _hasDetails = false;
|
||||
List<DateWithPrecisionAndCountry>? _releaseDates;
|
||||
|
@ -21,6 +22,10 @@ class MovieData extends ChangeNotifier {
|
|||
return _releaseDate;
|
||||
}
|
||||
|
||||
bool get bookmarked {
|
||||
return _bookmarked;
|
||||
}
|
||||
|
||||
List<DateWithPrecisionAndCountry>? 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<DateWithPrecisionAndCountry>? releaseDates,
|
||||
List<String>? genres,
|
||||
List<TitleInLanguage>? 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<dynamic>?)
|
||||
?.map((genre) => genre as String)
|
||||
.toList(),
|
||||
|
|
|
@ -54,7 +54,7 @@ class MovieManager extends ChangeNotifier {
|
|||
added = true;
|
||||
actualMovies.add(movie);
|
||||
} else {
|
||||
existing.updateWithNew(movie);
|
||||
existing.updateWithNewIgnoringUserControlled(movie);
|
||||
actualMovies.add(existing);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,14 @@ class MovieItem extends StatelessWidget {
|
|||
return ListTile(
|
||||
title: Text(movie.title),
|
||||
subtitle: Text(
|
||||
"${dateRelativeToNow(movie.releaseDate.date)}, ${movie.releaseDate.toString()}, ${movie.genres?.join(", ") ?? ""}"));
|
||||
"${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),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,28 @@ import 'package:release_schedule/view/movie_item.dart';
|
|||
|
||||
class MovieList extends StatelessWidget {
|
||||
final List<MovieData> 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<int> 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) {
|
||||
|
|
|
@ -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))
|
||||
],
|
||||
);
|
||||
},
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue