Compare commits
2 Commits
9aa0278ab0
...
92b4a302dc
Author | SHA1 | Date |
---|---|---|
daniel-michel | 92b4a302dc | |
daniel-michel | 0520120ccf |
|
@ -0,0 +1,85 @@
|
|||
import 'package:release_schedule/api/json_helper.dart';
|
||||
import 'package:release_schedule/api/wikidata/wikidata_movie_api.dart';
|
||||
import 'package:release_schedule/model/dates.dart';
|
||||
import 'package:release_schedule/model/movie.dart';
|
||||
|
||||
class WikidataMovieData extends MovieData {
|
||||
String entityId;
|
||||
WikidataMovieData(this.entityId);
|
||||
|
||||
WikidataMovieData.fromEncodable(Map encodable)
|
||||
: entityId = encodable["entityId"],
|
||||
super.fromJsonEncodable(encodable);
|
||||
|
||||
@override
|
||||
bool same(MovieData other) {
|
||||
return other is WikidataMovieData && entityId == other.entityId;
|
||||
}
|
||||
|
||||
@override
|
||||
Map toJsonEncodable() {
|
||||
return super.toJsonEncodable()..addAll({"entityId": entityId});
|
||||
}
|
||||
|
||||
static WikidataMovieData fromWikidataEntity(
|
||||
String entityId, Map<String, dynamic> entity) {
|
||||
Map<String, dynamic> claims = entity["claims"];
|
||||
List<TextInLanguage>? titles = selectInJson(
|
||||
claims, "${WikidataProperties.title}.*.mainsnak.datavalue.value")
|
||||
.map((value) => (
|
||||
text: value["text"],
|
||||
language: value["language"],
|
||||
) as TextInLanguage)
|
||||
.toList();
|
||||
List<TextInLanguage>? labels = selectInJson(entity, "labels.*")
|
||||
.map((value) => (
|
||||
text: value["value"],
|
||||
language: value["language"],
|
||||
) as TextInLanguage)
|
||||
.toList();
|
||||
String? wikipediaTitle = selectInJson(entity, "sitelinks.enwiki.url")
|
||||
.firstOrNull
|
||||
?.split("/")
|
||||
.last;
|
||||
Dated<String?>? description = wikipediaTitle != null
|
||||
? getCachedWikipediaExplainTextFotTitle(wikipediaTitle)
|
||||
: null;
|
||||
List<DateWithPrecisionAndCountry> releaseDates =
|
||||
_getReleaseDates(claims).toList();
|
||||
// Sort release dates with higher precision to the beginning
|
||||
releaseDates.sort((a, b) => -a.dateWithPrecision.precision.index
|
||||
.compareTo(b.dateWithPrecision.precision.index));
|
||||
List<String>? genres = selectInJson<String>(
|
||||
claims, "${WikidataProperties.genre}.*.mainsnak.datavalue.value.id")
|
||||
.map(getCachedLabelForEntity)
|
||||
.toList();
|
||||
WikidataMovieData movie = WikidataMovieData(entityId);
|
||||
movie.setDetails(
|
||||
titles: Dated.now(titles),
|
||||
labels: Dated.now(labels),
|
||||
releaseDates: Dated.now(releaseDates),
|
||||
genres: Dated.now(genres),
|
||||
description: description,
|
||||
);
|
||||
return movie;
|
||||
}
|
||||
|
||||
static Iterable<DateWithPrecisionAndCountry> _getReleaseDates(
|
||||
Map<String, dynamic> claims) {
|
||||
return selectInJson(claims, "${WikidataProperties.publicationDate}.*")
|
||||
.where((dateClaim) => dateClaim["rank"] != "deprecated")
|
||||
.expand<DateWithPrecisionAndCountry>((dateClaim) {
|
||||
var value = selectInJson(dateClaim, "mainsnak.datavalue.value").first;
|
||||
Iterable<String> countries = (selectInJson<String>(dateClaim,
|
||||
"qualifiers.${WikidataProperties.placeOfPublication}.*.datavalue.value.id"))
|
||||
.map(getCachedLabelForEntity);
|
||||
if (countries.isEmpty) {
|
||||
countries = ["unknown location"];
|
||||
}
|
||||
return countries.map((country) => DateWithPrecisionAndCountry(
|
||||
DateTime.parse(value["time"]),
|
||||
precisionFromWikidata(value["precision"]),
|
||||
country));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -6,8 +6,8 @@ import 'package:intl/intl.dart';
|
|||
import 'package:release_schedule/api/api_manager.dart';
|
||||
import 'package:release_schedule/api/json_helper.dart';
|
||||
import 'package:release_schedule/api/movie_api.dart';
|
||||
import 'package:release_schedule/api/wikidata/wikidata_movie.dart';
|
||||
import 'package:release_schedule/model/dates.dart';
|
||||
import 'package:release_schedule/model/movie.dart';
|
||||
|
||||
class WikidataProperties {
|
||||
static const String instanceOf = "P31";
|
||||
|
@ -75,7 +75,7 @@ class WikidataMovieApi implements MovieApi {
|
|||
final start = i * batchSize;
|
||||
final end = min((i + 1) * batchSize, movieIds.length);
|
||||
var response = await _wikidataApi.get(
|
||||
"&action=wbgetentities&format=json&props=labels|claims&ids=${movieIds.sublist(start, end).join("|")}");
|
||||
"&action=wbgetentities&format=json&props=labels|claims|sitelinks/urls&ids=${movieIds.sublist(start, end).join("|")}");
|
||||
Map<String, dynamic> result = jsonDecode(response.body);
|
||||
Map<String, dynamic> batchEntities = result["entities"];
|
||||
entities.addAll(batchEntities);
|
||||
|
@ -94,6 +94,12 @@ class WikidataMovieApi implements MovieApi {
|
|||
// they will be retrieved from the cache in fromWikidataEntity
|
||||
await _getLabelsForEntities(allCountryAndGenreIds);
|
||||
|
||||
// Get wikipedia explaintexts
|
||||
Iterable<String> allWikipediaTitles =
|
||||
selectInJson<String>(entities, "*.sitelinks.enwiki.url")
|
||||
.map((url) => url.split("/").last);
|
||||
await _getWikipediaExplainTextForTitles(allWikipediaTitles.toList());
|
||||
|
||||
return movieIds
|
||||
.map((id) => WikidataMovieData.fromWikidataEntity(id, entities[id]))
|
||||
.toList();
|
||||
|
@ -117,83 +123,6 @@ class WikidataMovieApi implements MovieApi {
|
|||
}
|
||||
}
|
||||
|
||||
class WikidataMovieData extends MovieData {
|
||||
String entityId;
|
||||
WikidataMovieData(
|
||||
String title, DateWithPrecisionAndCountry releaseDate, this.entityId)
|
||||
: super(title, releaseDate);
|
||||
|
||||
WikidataMovieData.fromEncodable(Map encodable)
|
||||
: entityId = encodable["entityId"],
|
||||
super.fromJsonEncodable(encodable);
|
||||
|
||||
@override
|
||||
bool same(MovieData other) {
|
||||
return other is WikidataMovieData && entityId == other.entityId;
|
||||
}
|
||||
|
||||
@override
|
||||
Map toJsonEncodable() {
|
||||
return super.toJsonEncodable()..addAll({"entityId": entityId});
|
||||
}
|
||||
|
||||
static WikidataMovieData fromWikidataEntity(
|
||||
String entityId, Map<String, dynamic> entity) {
|
||||
String title =
|
||||
selectInJson<String>(entity, "labels.en.value").firstOrNull ??
|
||||
selectInJson<String>(entity, "labels.*.value").first;
|
||||
Map<String, dynamic> claims = entity["claims"];
|
||||
List<TitleInLanguage>? titles = selectInJson(
|
||||
claims, "${WikidataProperties.title}.*.mainsnak.datavalue.value")
|
||||
.map((value) => (
|
||||
title: value["text"],
|
||||
language: value["language"],
|
||||
) as TitleInLanguage)
|
||||
.toList();
|
||||
List<DateWithPrecisionAndCountry> releaseDates =
|
||||
_getReleaseDates(claims).toList();
|
||||
// Sort release dates with higher precision to the beginning
|
||||
releaseDates.sort((a, b) => -a.dateWithPrecision.precision.index
|
||||
.compareTo(b.dateWithPrecision.precision.index));
|
||||
List<String>? genres = selectInJson<String>(
|
||||
claims, "${WikidataProperties.genre}.*.mainsnak.datavalue.value.id")
|
||||
.map(_getCachedLabelForEntity)
|
||||
.toList();
|
||||
WikidataMovieData movie = WikidataMovieData(
|
||||
title,
|
||||
releaseDates.isNotEmpty
|
||||
? releaseDates[0]
|
||||
: DateWithPrecisionAndCountry(
|
||||
DateTime.now(), DatePrecision.decade, "unknown location"),
|
||||
entityId);
|
||||
movie.setDetails(
|
||||
titles: titles,
|
||||
releaseDates: releaseDates,
|
||||
genres: genres,
|
||||
);
|
||||
return movie;
|
||||
}
|
||||
|
||||
static Iterable<DateWithPrecisionAndCountry> _getReleaseDates(
|
||||
Map<String, dynamic> claims) {
|
||||
return selectInJson(claims, "${WikidataProperties.publicationDate}.*")
|
||||
.where((dateClaim) => dateClaim["rank"] != "deprecated")
|
||||
.expand<DateWithPrecisionAndCountry>((dateClaim) {
|
||||
var value = selectInJson(dateClaim, "mainsnak.datavalue.value").first;
|
||||
Iterable<String> countries = (selectInJson<String>(dateClaim,
|
||||
"qualifiers.${WikidataProperties.placeOfPublication}.*.datavalue.value.id"))
|
||||
.map(_getCachedLabelForEntity);
|
||||
if (countries.isEmpty) {
|
||||
countries = ["unknown location"];
|
||||
}
|
||||
return countries.map((country) => DateWithPrecisionAndCountry(
|
||||
DateTime.parse(value["time"]),
|
||||
_precisionFromWikidata(value["precision"]),
|
||||
country));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
String _createUpcomingMovieQuery(
|
||||
DateTime startDate, String instanceOf, int limit) {
|
||||
String date = DateFormat("yyyy-MM-dd").format(startDate);
|
||||
|
@ -213,7 +142,7 @@ ORDER BY ?minReleaseDate
|
|||
LIMIT $limit""";
|
||||
}
|
||||
|
||||
DatePrecision _precisionFromWikidata(int precision) {
|
||||
DatePrecision precisionFromWikidata(int precision) {
|
||||
return switch (precision) {
|
||||
>= 13 => DatePrecision.minute,
|
||||
12 => DatePrecision.hour,
|
||||
|
@ -264,6 +193,48 @@ Future<Map<String, String>> _getLabelsForEntities(
|
|||
return labels;
|
||||
}
|
||||
|
||||
String _getCachedLabelForEntity(String entityId) {
|
||||
String getCachedLabelForEntity(String entityId) {
|
||||
return _labelCache[entityId] ?? entityId;
|
||||
}
|
||||
|
||||
ApiManager _wikipediaApi =
|
||||
ApiManager("https://en.wikipedia.org/w/api.php?format=json&origin=*");
|
||||
Map<String, Dated<String?>> _wikipediaExplainTextCache = {};
|
||||
|
||||
Future<Map<String, Dated<String?>>> _getWikipediaExplainTextForTitles(
|
||||
List<String> pageTitles) async {
|
||||
const batchSize = 50;
|
||||
Map<String, Dated<String?>> explainTexts = {};
|
||||
for (int i = pageTitles.length - 1; i >= 0; i--) {
|
||||
if (_wikipediaExplainTextCache.containsKey(pageTitles[i])) {
|
||||
explainTexts[pageTitles[i]] = _wikipediaExplainTextCache[pageTitles[i]]!;
|
||||
pageTitles.removeAt(i);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < (pageTitles.length / batchSize).ceil(); i++) {
|
||||
final start = i * batchSize;
|
||||
final end = min((i + 1) * batchSize, pageTitles.length);
|
||||
Response response = await _wikipediaApi.get(
|
||||
"&action=query&prop=extracts&exintro&explaintext&redirects=1&titles=${pageTitles.sublist(start, end).join("|")}");
|
||||
Map<String, dynamic> result = jsonDecode(response.body);
|
||||
List<dynamic> normalize = result["query"]["normalized"];
|
||||
Map<String, dynamic> batchPages = result["query"]["pages"];
|
||||
for (String pageId in batchPages.keys) {
|
||||
String pageTitle = batchPages[pageId]["title"];
|
||||
String originalTitle = normalize
|
||||
.where((element) => element["to"] == pageTitle)
|
||||
.firstOrNull?["from"] ??
|
||||
pageTitle;
|
||||
String? explainText = batchPages[pageId]["extract"];
|
||||
if (explainText != null) {
|
||||
_wikipediaExplainTextCache[originalTitle] =
|
||||
explainTexts[originalTitle] = Dated.now(explainText);
|
||||
}
|
||||
}
|
||||
}
|
||||
return explainTexts;
|
||||
}
|
||||
|
||||
Dated<String?>? getCachedWikipediaExplainTextFotTitle(String title) {
|
||||
return _wikipediaExplainTextCache[title];
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:release_schedule/api/wikidata_movie_api.dart';
|
||||
import 'package:release_schedule/api/wikidata/wikidata_movie.dart';
|
||||
import 'package:release_schedule/api/wikidata/wikidata_movie_api.dart';
|
||||
import 'package:release_schedule/model/dates.dart';
|
||||
import 'package:release_schedule/model/live_search.dart';
|
||||
import 'package:release_schedule/model/local_movie_storage.dart';
|
||||
|
@ -17,6 +18,10 @@ class MyApp extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final MovieManager manager = MovieManager(
|
||||
WikidataMovieApi(),
|
||||
LocalMovieStorageGetStorage(WikidataMovieData.fromEncodable),
|
||||
);
|
||||
return MaterialApp(
|
||||
title: 'Movie Schedule',
|
||||
themeMode: ThemeMode.dark,
|
||||
|
@ -32,10 +37,7 @@ class MyApp extends StatelessWidget {
|
|||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: HomePage(
|
||||
MovieManager(WikidataMovieApi(),
|
||||
LocalMovieStorageGetStorage(WikidataMovieData.fromEncodable)),
|
||||
),
|
||||
home: HomePage(manager),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -187,9 +189,10 @@ class OverviewPage extends StatelessWidget {
|
|||
// Only show movies that are bookmarked or have a release date with at least month precision and at least one title
|
||||
filter: (movie) =>
|
||||
movie.bookmarked ||
|
||||
(movie.releaseDate.dateWithPrecision.precision >=
|
||||
(movie.releaseDate != null &&
|
||||
movie.releaseDate!.dateWithPrecision.precision >=
|
||||
DatePrecision.month &&
|
||||
(movie.titles?.length ?? 0) >= 1),
|
||||
(movie.titles?.value?.length ?? 0) >= 1),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: const Icon(Icons.refresh),
|
||||
|
@ -234,7 +237,7 @@ class HamburgerMenu extends StatelessWidget {
|
|||
child: const Text("Remove irrelevant"),
|
||||
onTap: () => manager.removeMoviesWhere((movie) =>
|
||||
!movie.bookmarked &&
|
||||
!(movie.releaseDates?.any((date) =>
|
||||
!(movie.releaseDates?.value?.any((date) =>
|
||||
date.dateWithPrecision.precision >=
|
||||
DatePrecision.month &&
|
||||
date.dateWithPrecision.date.isAfter(DateTime.now()
|
||||
|
|
|
@ -55,6 +55,7 @@ class DateWithPrecision implements Comparable<DateWithPrecision> {
|
|||
.firstWhere((element) => element.name == json[1]);
|
||||
|
||||
DateWithPrecision.today() : this(DateTime.now().toUtc(), DatePrecision.day);
|
||||
DateWithPrecision.unspecified() : this(DateTime(0), DatePrecision.decade);
|
||||
|
||||
List<dynamic> toJsonEncodable() {
|
||||
return [date.toIso8601String(), precision.name];
|
||||
|
@ -122,3 +123,28 @@ class DateWithPrecision implements Comparable<DateWithPrecision> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Dated<T> {
|
||||
final T value;
|
||||
final DateTime date;
|
||||
|
||||
Dated(this.value, this.date);
|
||||
|
||||
Dated.now(this.value) : date = DateTime.now().toUtc();
|
||||
|
||||
Dated.fromJsonEncodable(
|
||||
dynamic json, T Function(dynamic) valueFromJsonEncodable)
|
||||
: value = valueFromJsonEncodable(json["value"]),
|
||||
date = DateTime.parse(json["date"]);
|
||||
|
||||
Map<String, dynamic> toJsonEncodable(
|
||||
dynamic Function(T) valueToJsonEncodable) {
|
||||
return {
|
||||
"value": valueToJsonEncodable(value),
|
||||
"date": date.toIso8601String()
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
toString() => "$value as of $date";
|
||||
}
|
||||
|
|
|
@ -2,22 +2,26 @@ import 'package:flutter/material.dart';
|
|||
import 'package:release_schedule/model/dates.dart';
|
||||
|
||||
class MovieData extends ChangeNotifier {
|
||||
String _title;
|
||||
DateWithPrecisionAndCountry _releaseDate;
|
||||
bool _bookmarked = false;
|
||||
|
||||
bool _hasDetails = false;
|
||||
List<DateWithPrecisionAndCountry>? _releaseDates;
|
||||
List<String>? _genres;
|
||||
List<TitleInLanguage>? _titles;
|
||||
String? _title;
|
||||
DateWithPrecisionAndCountry? _releaseDate;
|
||||
|
||||
MovieData(this._title, this._releaseDate);
|
||||
// if it is entirely null the information was never loaded
|
||||
// if only the value is null it was loaded but nothing was found
|
||||
Dated<List<TextInLanguage>?>? _titles;
|
||||
Dated<List<TextInLanguage>?>? _labels;
|
||||
Dated<List<DateWithPrecisionAndCountry>?>? _releaseDates;
|
||||
Dated<String?>? _description;
|
||||
Dated<List<String>?>? _genres;
|
||||
|
||||
String get title {
|
||||
MovieData();
|
||||
|
||||
String? get title {
|
||||
return _title;
|
||||
}
|
||||
|
||||
DateWithPrecisionAndCountry get releaseDate {
|
||||
DateWithPrecisionAndCountry? get releaseDate {
|
||||
return _releaseDate;
|
||||
}
|
||||
|
||||
|
@ -25,111 +29,188 @@ class MovieData extends ChangeNotifier {
|
|||
return _bookmarked;
|
||||
}
|
||||
|
||||
List<DateWithPrecisionAndCountry>? get releaseDates {
|
||||
Dated<String?>? get description {
|
||||
return _description;
|
||||
}
|
||||
|
||||
Dated<List<DateWithPrecisionAndCountry>?>? get releaseDates {
|
||||
return _releaseDates;
|
||||
}
|
||||
|
||||
List<String>? get genres {
|
||||
Dated<List<String>?>? get genres {
|
||||
return _genres;
|
||||
}
|
||||
|
||||
List<TitleInLanguage>? get titles {
|
||||
Dated<List<TextInLanguage>?>? get titles {
|
||||
return _titles;
|
||||
}
|
||||
|
||||
bool get hasDetails {
|
||||
return _hasDetails;
|
||||
Dated<List<TextInLanguage>?>? get labels {
|
||||
return _labels;
|
||||
}
|
||||
|
||||
/// 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,
|
||||
releaseDates: movie.releaseDates,
|
||||
genres: movie.genres,
|
||||
titles: movie.titles);
|
||||
titles: movie.titles,
|
||||
labels: movie.labels,
|
||||
releaseDates: movie.releaseDates,
|
||||
genres: movie.genres,
|
||||
description: movie.description,
|
||||
);
|
||||
}
|
||||
|
||||
void setDetails(
|
||||
{String? title,
|
||||
DateWithPrecisionAndCountry? releaseDate,
|
||||
bool? bookmarked,
|
||||
List<DateWithPrecisionAndCountry>? releaseDates,
|
||||
List<String>? genres,
|
||||
List<TitleInLanguage>? titles}) {
|
||||
if (title != null) {
|
||||
_title = title;
|
||||
}
|
||||
if (releaseDate != null) {
|
||||
_releaseDate = releaseDate;
|
||||
}
|
||||
void setNewDetails({
|
||||
bool? bookmarked,
|
||||
List<TextInLanguage>? titles,
|
||||
List<TextInLanguage>? labels,
|
||||
List<DateWithPrecisionAndCountry>? releaseDates,
|
||||
List<String>? genres,
|
||||
String? description,
|
||||
}) {
|
||||
setDetails(
|
||||
bookmarked: bookmarked,
|
||||
titles: titles != null ? Dated.now(titles) : null,
|
||||
labels: labels != null ? Dated.now(labels) : null,
|
||||
releaseDates: releaseDates != null ? Dated.now(releaseDates) : null,
|
||||
genres: genres != null ? Dated.now(genres) : null,
|
||||
description: description != null ? Dated.now(description) : null,
|
||||
);
|
||||
}
|
||||
|
||||
void setDetails({
|
||||
bool? bookmarked,
|
||||
Dated<List<TextInLanguage>?>? titles,
|
||||
Dated<List<TextInLanguage>?>? labels,
|
||||
Dated<List<DateWithPrecisionAndCountry>?>? releaseDates,
|
||||
Dated<List<String>?>? genres,
|
||||
Dated<String?>? description,
|
||||
}) {
|
||||
if (bookmarked != null) {
|
||||
_bookmarked = bookmarked;
|
||||
}
|
||||
if (releaseDates != null) {
|
||||
_releaseDates = releaseDates;
|
||||
}
|
||||
if (genres != null) {
|
||||
_genres = genres;
|
||||
}
|
||||
if (titles != null) {
|
||||
_titles = titles;
|
||||
}
|
||||
_hasDetails = true;
|
||||
if (labels != null) {
|
||||
_labels = labels;
|
||||
}
|
||||
if (titles != null || labels != null) {
|
||||
_title = null;
|
||||
_title ??= _titles?.value
|
||||
?.where((title) => title.language == "en")
|
||||
.firstOrNull
|
||||
?.text;
|
||||
_title ??= _labels?.value
|
||||
?.where((label) => label.language == "en")
|
||||
.firstOrNull
|
||||
?.text;
|
||||
_title ??= _labels?.value?.firstOrNull?.text;
|
||||
_title ??= _titles?.value?.firstOrNull?.text;
|
||||
}
|
||||
if (description != null) {
|
||||
_description = description;
|
||||
}
|
||||
if (releaseDates != null) {
|
||||
_releaseDates = releaseDates;
|
||||
DateWithPrecisionAndCountry? mostPrecise =
|
||||
_releaseDates?.value?.isNotEmpty ?? false
|
||||
? _releaseDates?.value?.reduce((a, b) =>
|
||||
a.dateWithPrecision.precision > b.dateWithPrecision.precision
|
||||
? a
|
||||
: b)
|
||||
: null;
|
||||
_releaseDate = mostPrecise;
|
||||
}
|
||||
if (genres != null) {
|
||||
_genres = genres;
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "$title (${_releaseDate.toString()}${_genres?.isNotEmpty ?? false ? "; ${_genres?.join(", ")}" : ""})";
|
||||
return "$title (${_releaseDate.toString()}${_genres?.value?.isNotEmpty ?? false ? "; ${_genres?.value?.join(", ")}" : ""})";
|
||||
}
|
||||
|
||||
bool same(MovieData other) {
|
||||
return title == other.title &&
|
||||
releaseDate.dateWithPrecision == other.releaseDate.dateWithPrecision;
|
||||
return title != null &&
|
||||
title == other.title &&
|
||||
(releaseDate == null ||
|
||||
other.releaseDate == null ||
|
||||
releaseDate!.dateWithPrecision.date.year ==
|
||||
other.releaseDate!.dateWithPrecision.date.year);
|
||||
}
|
||||
|
||||
Map toJsonEncodable() {
|
||||
List? releaseDatesByCountry =
|
||||
_releaseDates?.map((e) => e.toJsonEncodable()).toList();
|
||||
List? titlesByCountry = _titles?.map((e) => [e.title, e.language]).toList();
|
||||
dynamic releaseDatesByCountry = _releaseDates?.toJsonEncodable(
|
||||
(releaseDates) => releaseDates
|
||||
?.map((releaseDate) => releaseDate.toJsonEncodable())
|
||||
.toList());
|
||||
dynamic titlesByCountry = _titles?.toJsonEncodable(
|
||||
(titles) => titles?.map((e) => [e.text, e.language]).toList());
|
||||
dynamic labels = _labels?.toJsonEncodable(
|
||||
(labels) => labels?.map((e) => [e.text, e.language]).toList());
|
||||
dynamic genres = _genres?.toJsonEncodable((genres) => genres);
|
||||
return {
|
||||
"title": title,
|
||||
"releaseDate": _releaseDate.toJsonEncodable(),
|
||||
"bookmarked": _bookmarked,
|
||||
"titles": titlesByCountry,
|
||||
"labels": labels,
|
||||
"releaseDates": releaseDatesByCountry,
|
||||
"genres": genres,
|
||||
"titles": titlesByCountry,
|
||||
"description":
|
||||
_description?.toJsonEncodable((description) => description),
|
||||
};
|
||||
}
|
||||
|
||||
MovieData.fromJsonEncodable(Map json)
|
||||
: _title = json["title"],
|
||||
_releaseDate =
|
||||
DateWithPrecisionAndCountry.fromJsonEncodable(json["releaseDate"]) {
|
||||
MovieData.fromJsonEncodable(Map json) {
|
||||
setDetails(
|
||||
bookmarked: json["bookmarked"] as bool,
|
||||
genres: (json["genres"] as List<dynamic>?)
|
||||
?.map((genre) => genre as String)
|
||||
.toList(),
|
||||
releaseDates: json["releaseDates"] != null
|
||||
? (json["releaseDates"] as List<dynamic>)
|
||||
.map((release) =>
|
||||
DateWithPrecisionAndCountry.fromJsonEncodable(release))
|
||||
.toList()
|
||||
: null,
|
||||
titles: json["titles"] != null
|
||||
? (json["titles"] as List<dynamic>)
|
||||
.map((title) =>
|
||||
(title: title[0], language: title[1]) as TitleInLanguage)
|
||||
.toList()
|
||||
: null);
|
||||
bookmarked: json["bookmarked"] as bool? ?? false,
|
||||
titles: decodeOptionalJson<Dated<List<TextInLanguage>?>>(
|
||||
json["titles"],
|
||||
(json) => Dated.fromJsonEncodable(
|
||||
json,
|
||||
(value) => (value as List<dynamic>)
|
||||
.map((title) =>
|
||||
(text: title[0], language: title[1]) as TextInLanguage)
|
||||
.toList())),
|
||||
labels: decodeOptionalJson<Dated<List<TextInLanguage>?>>(
|
||||
json["labels"],
|
||||
(json) => Dated.fromJsonEncodable(
|
||||
json,
|
||||
(value) => (value as List<dynamic>)
|
||||
.map((label) =>
|
||||
(text: label[0], language: label[1]) as TextInLanguage)
|
||||
.toList())),
|
||||
genres: decodeOptionalJson<Dated<List<String>?>>(
|
||||
json["genres"],
|
||||
(json) =>
|
||||
Dated.fromJsonEncodable(json, (value) => value.cast<String>())),
|
||||
releaseDates:
|
||||
decodeOptionalJson<Dated<List<DateWithPrecisionAndCountry>?>>(
|
||||
json["releaseDates"],
|
||||
(json) => Dated.fromJsonEncodable(
|
||||
json,
|
||||
(value) => (value as List<dynamic>)
|
||||
.map((releaseDate) =>
|
||||
DateWithPrecisionAndCountry.fromJsonEncodable(
|
||||
releaseDate))
|
||||
.toList())),
|
||||
description: decodeOptionalJson<Dated<String?>>(json["description"],
|
||||
(json) => Dated.fromJsonEncodable(json, (value) => value)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
typedef TitleInLanguage = ({String title, String language});
|
||||
T? decodeOptionalJson<T>(dynamic json, T Function(dynamic) decode) {
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
return decode(json);
|
||||
}
|
||||
|
||||
typedef TextInLanguage = ({String text, String language});
|
||||
|
||||
class DateWithPrecisionAndCountry {
|
||||
final DateWithPrecision dateWithPrecision;
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:release_schedule/api/movie_api.dart';
|
||||
import 'package:release_schedule/model/dates.dart';
|
||||
import 'package:release_schedule/model/delayed_function_caller.dart';
|
||||
import 'package:release_schedule/model/local_movie_storage.dart';
|
||||
import 'package:release_schedule/model/movie.dart';
|
||||
|
@ -64,11 +65,15 @@ class MovieManager extends ChangeNotifier {
|
|||
void _insertMovie(MovieData movie) {
|
||||
int min = 0;
|
||||
int max = movies.length - 1;
|
||||
DateWithPrecision? movieDate = movie.releaseDate?.dateWithPrecision;
|
||||
while (min <= max) {
|
||||
int center = (min + max) ~/ 2;
|
||||
int diff = movie.releaseDate.dateWithPrecision
|
||||
.compareTo(movies[center].releaseDate.dateWithPrecision);
|
||||
if (diff < 0) {
|
||||
DateWithPrecision? centerDate =
|
||||
movies[center].releaseDate?.dateWithPrecision;
|
||||
int diff = movieDate != null && centerDate != null
|
||||
? movieDate.compareTo(centerDate)
|
||||
: 0;
|
||||
if (movieDate == null || centerDate != null && diff < 0) {
|
||||
max = center - 1;
|
||||
} else {
|
||||
min = center + 1;
|
||||
|
@ -80,15 +85,13 @@ class MovieManager extends ChangeNotifier {
|
|||
void _resortMovies() {
|
||||
for (int i = 0; i < movies.length; i++) {
|
||||
var temp = movies[i];
|
||||
DateWithPrecision? tempDate = temp.releaseDate?.dateWithPrecision;
|
||||
int j = i - 1;
|
||||
for (;
|
||||
j >= 0 &&
|
||||
movies[j]
|
||||
.releaseDate
|
||||
.dateWithPrecision
|
||||
.compareTo(temp.releaseDate.dateWithPrecision) >
|
||||
0;
|
||||
j--) {
|
||||
for (; j >= 0; j--) {
|
||||
DateWithPrecision? date = movies[j].releaseDate?.dateWithPrecision;
|
||||
if (date == null || tempDate != null && date.compareTo(tempDate) <= 0) {
|
||||
break;
|
||||
}
|
||||
movies[j + 1] = movies[j];
|
||||
}
|
||||
movies[j + 1] = temp;
|
||||
|
@ -115,8 +118,8 @@ class MovieManager extends ChangeNotifier {
|
|||
movies,
|
||||
search,
|
||||
(movie) => [
|
||||
movie.title,
|
||||
...(movie.titles?.map((title) => title.title) ?? []),
|
||||
movie.title ?? "",
|
||||
...(movie.titles?.value?.map((title) => title.text) ?? []),
|
||||
]);
|
||||
return results;
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@ class MovieItem extends StatelessWidget {
|
|||
animation: movie,
|
||||
builder: (context, widget) {
|
||||
return ListTile(
|
||||
title: Text(movie.title),
|
||||
title: Text(movie.title ?? "-"),
|
||||
subtitle: Text(
|
||||
(showReleaseDate ? "${movie.releaseDate} " : "") +
|
||||
(movie.genres?.join(", ") ?? ""),
|
||||
(movie.genres?.value?.join(", ") ?? ""),
|
||||
),
|
||||
trailing: IconButton(
|
||||
icon: Icon(movie.bookmarked
|
||||
|
|
|
@ -78,9 +78,9 @@ class MovieList extends StatelessWidget {
|
|||
int max = indexMap.length;
|
||||
while (min < max) {
|
||||
int center = (min + max) ~/ 2;
|
||||
DateWithPrecision date =
|
||||
movies[indexMap[center]].releaseDate.dateWithPrecision;
|
||||
if (date.compareTo(today) < 0) {
|
||||
DateWithPrecision? date =
|
||||
movies[indexMap[center]].releaseDate?.dateWithPrecision;
|
||||
if (date != null && date.compareTo(today) < 0) {
|
||||
min = center + 1;
|
||||
} else {
|
||||
max = center;
|
||||
|
@ -91,7 +91,8 @@ class MovieList extends StatelessWidget {
|
|||
return GroupedList<DateWithPrecision>(
|
||||
itemCount: indexMap.length,
|
||||
groupBy: (index) =>
|
||||
movies[indexMap[index]].releaseDate.dateWithPrecision,
|
||||
movies[indexMap[index]].releaseDate?.dateWithPrecision ??
|
||||
DateWithPrecision.unspecified(),
|
||||
groupSeparatorBuilder: (date) => buildGroupSeparator(context, date),
|
||||
itemBuilder: (context, index) {
|
||||
return MovieItem(movies[indexMap[index]]);
|
||||
|
@ -106,8 +107,8 @@ class MovieList extends StatelessWidget {
|
|||
int max = movies.length;
|
||||
while (min < max) {
|
||||
int center = (min + max) ~/ 2;
|
||||
DateWithPrecision date = movies[center].releaseDate.dateWithPrecision;
|
||||
if (date.compareTo(today) < 0) {
|
||||
DateWithPrecision? date = movies[center].releaseDate?.dateWithPrecision;
|
||||
if (date != null && date.compareTo(today) < 0) {
|
||||
min = center + 1;
|
||||
} else {
|
||||
max = center;
|
||||
|
@ -117,7 +118,9 @@ class MovieList extends StatelessWidget {
|
|||
}();
|
||||
return GroupedList<DateWithPrecision>(
|
||||
itemCount: movies.length,
|
||||
groupBy: (index) => movies[index].releaseDate.dateWithPrecision,
|
||||
groupBy: (index) =>
|
||||
movies[index].releaseDate?.dateWithPrecision ??
|
||||
DateWithPrecision.unspecified(),
|
||||
groupSeparatorBuilder: (date) => buildGroupSeparator(context, date),
|
||||
itemBuilder: (context, index) {
|
||||
return MovieItem(movies[index]);
|
||||
|
|
|
@ -29,7 +29,7 @@ class MoviePage extends StatelessWidget {
|
|||
animation: movie,
|
||||
builder: (context, child) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(movie.title), actions: [
|
||||
appBar: AppBar(title: Text(movie.title ?? "-"), actions: [
|
||||
IconButton(
|
||||
icon: Icon(movie.bookmarked
|
||||
? Icons.bookmark_added
|
||||
|
@ -39,19 +39,27 @@ class MoviePage extends StatelessWidget {
|
|||
]),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
padding: const EdgeInsets.all(18.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Wrap(
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
children: movie.genres
|
||||
children: movie.genres?.value
|
||||
?.map((genre) => Chip(label: Text(genre)))
|
||||
.toList() ??
|
||||
[],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const Heading("About"),
|
||||
Text(
|
||||
movie.description?.value?.trim().replaceAll("\n", "\n\n") ??
|
||||
"-",
|
||||
textAlign: TextAlign.justify,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
height: 1.6,
|
||||
),
|
||||
),
|
||||
const Heading("Titles"),
|
||||
Table(
|
||||
border: TableBorder.symmetric(
|
||||
|
@ -59,7 +67,7 @@ class MoviePage extends StatelessWidget {
|
|||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
),
|
||||
children: movie.titles?.map((title) {
|
||||
children: movie.titles?.value?.map((title) {
|
||||
return TableRow(
|
||||
children: [
|
||||
TableCell(
|
||||
|
@ -70,7 +78,7 @@ class MoviePage extends StatelessWidget {
|
|||
TableCell(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(title.title),
|
||||
child: Text(title.text),
|
||||
))
|
||||
],
|
||||
);
|
||||
|
@ -84,7 +92,7 @@ class MoviePage extends StatelessWidget {
|
|||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
),
|
||||
children: movie.releaseDates?.map((releaseDate) {
|
||||
children: movie.releaseDates?.value?.map((releaseDate) {
|
||||
return TableRow(
|
||||
children: [
|
||||
TableCell(
|
||||
|
|
|
@ -9,6 +9,23 @@ void main() {
|
|||
group('MovieManager', () {
|
||||
late MovieManager movieManager;
|
||||
|
||||
final theMatrix = MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'The Matrix', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1999, 3, 31), DatePrecision.day, 'USA')
|
||||
],
|
||||
);
|
||||
final theMatrixReloaded = MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'The Matrix Reloaded', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2003, 5, 7), DatePrecision.day, 'USA')
|
||||
],
|
||||
);
|
||||
|
||||
setUp(() {
|
||||
movieManager = MovieManager(
|
||||
MovieApi(),
|
||||
|
@ -18,16 +35,8 @@ void main() {
|
|||
|
||||
test('addMovies should add movies to the list', () {
|
||||
final movies = [
|
||||
MovieData(
|
||||
'The Matrix',
|
||||
DateWithPrecisionAndCountry(DateTime(1999, 3, 31), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData(
|
||||
'The Matrix Reloaded',
|
||||
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrix),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrixReloaded),
|
||||
];
|
||||
|
||||
movieManager.addMovies(movies);
|
||||
|
@ -37,56 +46,45 @@ void main() {
|
|||
|
||||
test('addMovies should add new movies', () {
|
||||
final movies = [
|
||||
MovieData(
|
||||
'The Matrix',
|
||||
DateWithPrecisionAndCountry(DateTime(1999, 3, 31), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData(
|
||||
'The Matrix Reloaded',
|
||||
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrix),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrixReloaded),
|
||||
];
|
||||
|
||||
movieManager.addMovies(movies);
|
||||
|
||||
final newMovies = [
|
||||
MovieData(
|
||||
'The Matrix Revolutions',
|
||||
DateWithPrecisionAndCountry(DateTime(2003, 11, 5), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'The Matrix Revolutions', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2003, 11, 5), DatePrecision.day, 'USA')
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
movieManager.addMovies(newMovies);
|
||||
|
||||
expect(movieManager.movies, equals([...movies, ...newMovies]));
|
||||
expect(movieManager.movies, equals(movies + newMovies));
|
||||
});
|
||||
|
||||
test('addMovies should update existing movies', () {
|
||||
final movies = [
|
||||
MovieData(
|
||||
'The Matrix',
|
||||
DateWithPrecisionAndCountry(DateTime(1999, 3, 31), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData(
|
||||
'The Matrix Reloaded',
|
||||
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrix),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrixReloaded),
|
||||
];
|
||||
|
||||
movieManager.addMovies(movies);
|
||||
|
||||
final updatedMovie = MovieData(
|
||||
'The Matrix Reloaded',
|
||||
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||
'United States of America'),
|
||||
)..setDetails(
|
||||
final updatedMovie = MovieData()
|
||||
..setNewDetails(
|
||||
bookmarked: true,
|
||||
genres: ['Action', 'Adventure'],
|
||||
labels: [(text: 'The Matrix Reloaded', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2003, 5, 7), DatePrecision.day, 'USA')
|
||||
],
|
||||
);
|
||||
|
||||
movieManager.addMovies([updatedMovie]);
|
||||
|
@ -97,37 +95,35 @@ void main() {
|
|||
|
||||
test('addMovies should sort movies by their release dates', () {
|
||||
final movies = [
|
||||
MovieData(
|
||||
'The Matrix Reloaded',
|
||||
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData(
|
||||
'The Matrix',
|
||||
DateWithPrecisionAndCountry(DateTime(1999, 3, 31), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrixReloaded),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrix),
|
||||
];
|
||||
|
||||
movieManager.addMovies(movies);
|
||||
|
||||
expect(movieManager.movies, equals([...movies.reversed]));
|
||||
expect(movieManager.movies, equals(movies.reversed.toList()));
|
||||
});
|
||||
|
||||
test(
|
||||
'addMovies should sort movies that have a less precise release date before movies with more precise release dates',
|
||||
() {
|
||||
final movies = [
|
||||
MovieData(
|
||||
'The Matrix Reloaded',
|
||||
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData(
|
||||
'The Matrix',
|
||||
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.month,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData()
|
||||
..updateWithNewIgnoringUserControlled(theMatrixReloaded)
|
||||
..setNewDetails(
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2003, 5, 7), DatePrecision.day, 'USA')
|
||||
],
|
||||
),
|
||||
MovieData()
|
||||
..updateWithNewIgnoringUserControlled(theMatrix)
|
||||
..setNewDetails(
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2003, 5, 7), DatePrecision.month, 'USA')
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
movieManager.addMovies(movies);
|
||||
|
@ -139,68 +135,59 @@ void main() {
|
|||
'when a movie is modified and it\'s date is changed the movies should be resorted',
|
||||
() async {
|
||||
final movies = [
|
||||
MovieData(
|
||||
'The Matrix Reloaded',
|
||||
DateWithPrecisionAndCountry(DateTime(1998, 5, 7), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData(
|
||||
'The Matrix',
|
||||
DateWithPrecisionAndCountry(DateTime(1999, 3, 31), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData()
|
||||
..updateWithNewIgnoringUserControlled(theMatrixReloaded)
|
||||
..setNewDetails(
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1998, 5, 7), DatePrecision.day, 'USA')
|
||||
],
|
||||
),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrix),
|
||||
];
|
||||
|
||||
movieManager.addMovies(movies);
|
||||
|
||||
final movie = movieManager.movies.first;
|
||||
movie.setDetails(
|
||||
releaseDate: DateWithPrecisionAndCountry(DateTime(2003, 5, 7),
|
||||
DatePrecision.day, 'United States of America'),
|
||||
movie.setNewDetails(
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||
'United States of America')
|
||||
],
|
||||
);
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
expect(movieManager.movies, equals([...movies.reversed]));
|
||||
expect(movieManager.movies, equals(movies.reversed.toList()));
|
||||
});
|
||||
|
||||
test('removeMoviesWhere should remove movies from the list', () {
|
||||
final movies = [
|
||||
MovieData(
|
||||
'The Matrix',
|
||||
DateWithPrecisionAndCountry(DateTime(1999, 3, 31), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData(
|
||||
'The Matrix Reloaded',
|
||||
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrix),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrixReloaded),
|
||||
];
|
||||
MovieData notRemoved = MovieData(
|
||||
'Harry Potter and the Philosopher\'s Stone',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2001, 11, 4), DatePrecision.day, 'United Kingdom'),
|
||||
);
|
||||
MovieData notRemoved = MovieData()
|
||||
..setNewDetails(
|
||||
labels: [
|
||||
(text: 'Harry Potter and the Philosopher\'s Stone', language: 'en')
|
||||
],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2001, 11, 4), DatePrecision.day, 'UK')
|
||||
],
|
||||
);
|
||||
|
||||
movieManager.addMovies([...movies, notRemoved]);
|
||||
movieManager.addMovies(movies + [notRemoved]);
|
||||
|
||||
movieManager.removeMoviesWhere((movie) => movie.title.contains('Matrix'));
|
||||
movieManager.removeMoviesWhere(
|
||||
(movie) => movie.title?.contains('Matrix') == true);
|
||||
|
||||
expect(movieManager.movies, equals([notRemoved]));
|
||||
});
|
||||
|
||||
test("localSearch", () {
|
||||
final movies = [
|
||||
MovieData(
|
||||
'The Matrix',
|
||||
DateWithPrecisionAndCountry(DateTime(1999, 3, 31), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData(
|
||||
'The Matrix Reloaded',
|
||||
DateWithPrecisionAndCountry(DateTime(2003, 5, 7), DatePrecision.day,
|
||||
'United States of America'),
|
||||
),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrix),
|
||||
MovieData()..updateWithNewIgnoringUserControlled(theMatrixReloaded),
|
||||
];
|
||||
|
||||
movieManager.addMovies(movies);
|
||||
|
|
|
@ -4,114 +4,108 @@ import 'package:release_schedule/model/movie.dart';
|
|||
|
||||
void main() {
|
||||
group('MovieData', () {
|
||||
MovieData firstMovie = MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'Title 1', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')
|
||||
],
|
||||
);
|
||||
MovieData secondMovie = MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'Title 2', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')
|
||||
],
|
||||
);
|
||||
|
||||
test('updateWithNew() updates all fields', () {
|
||||
final movie1 = MovieData(
|
||||
'Title 1',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
|
||||
final movie2 = MovieData(
|
||||
'Title 2',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'UK'));
|
||||
movie2.setDetails(releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')
|
||||
], genres: [
|
||||
'Action',
|
||||
'Adventure'
|
||||
], titles: [
|
||||
(title: 'Title 2', language: 'en')
|
||||
]);
|
||||
final movie1 = MovieData()
|
||||
..updateWithNewIgnoringUserControlled(firstMovie);
|
||||
final movie2 = MovieData()
|
||||
..updateWithNewIgnoringUserControlled(secondMovie)
|
||||
..setNewDetails(
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'UK')
|
||||
],
|
||||
genres: ['Action', 'Adventure'],
|
||||
titles: [(text: 'Titel 2', language: 'de')],
|
||||
);
|
||||
movie1.updateWithNewIgnoringUserControlled(movie2);
|
||||
expect(movie1.title, equals('Title 2'));
|
||||
expect(movie1.releaseDate.country, equals('UK'));
|
||||
expect(movie1.releaseDates!.length, equals(1));
|
||||
expect(movie1.releaseDates![0].country, equals('US'));
|
||||
expect(movie1.genres!.length, equals(2));
|
||||
expect(movie1.genres![0], equals('Action'));
|
||||
expect(movie1.genres![1], equals('Adventure'));
|
||||
expect(movie1.titles!.length, equals(1));
|
||||
expect(movie1.titles![0].title, equals('Title 2'));
|
||||
expect(movie1.titles![0].language, equals('en'));
|
||||
expect(movie1.releaseDate?.country, equals('UK'));
|
||||
expect(movie1.releaseDates?.value?.length, equals(1));
|
||||
expect(movie1.releaseDates?.value?[0].country, equals('UK'));
|
||||
expect(movie1.genres?.value?.length, equals(2));
|
||||
expect(movie1.genres?.value?[0], equals('Action'));
|
||||
expect(movie1.genres?.value?[1], equals('Adventure'));
|
||||
expect(movie1.titles?.value?.length, equals(1));
|
||||
expect(movie1.titles?.value?[0].text, equals('Titel 2'));
|
||||
expect(movie1.titles?.value?[0].language, equals('de'));
|
||||
});
|
||||
|
||||
test('same() returns true for same title and release date', () {
|
||||
final movie1 = MovieData(
|
||||
'Title 1',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
|
||||
final movie2 = MovieData(
|
||||
'Title 1',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
|
||||
test('same() returns true for same title and release year', () {
|
||||
final movie1 = MovieData()
|
||||
..updateWithNewIgnoringUserControlled(firstMovie);
|
||||
final movie2 = MovieData()
|
||||
..updateWithNewIgnoringUserControlled(firstMovie)
|
||||
..setNewDetails(
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 4, 27), DatePrecision.day, 'US')
|
||||
],
|
||||
);
|
||||
expect(movie1.same(movie2), isTrue);
|
||||
});
|
||||
|
||||
test('same() returns false for different title', () {
|
||||
final movie1 = MovieData(
|
||||
'Title 1',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
|
||||
final movie2 = MovieData(
|
||||
'Title 2',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
|
||||
final movie1 = MovieData()
|
||||
..updateWithNewIgnoringUserControlled(firstMovie);
|
||||
final movie2 = MovieData()
|
||||
..updateWithNewIgnoringUserControlled(secondMovie);
|
||||
expect(movie1.same(movie2), isFalse);
|
||||
});
|
||||
|
||||
test('same() returns false for different release date', () {
|
||||
final movie1 = MovieData(
|
||||
'Title 1',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
|
||||
final movie2 = MovieData(
|
||||
'Title 1',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 2), DatePrecision.day, 'US'));
|
||||
test('same() returns false for different release years', () {
|
||||
final movie1 = MovieData()
|
||||
..updateWithNewIgnoringUserControlled(firstMovie);
|
||||
final movie2 = MovieData()
|
||||
..updateWithNewIgnoringUserControlled(firstMovie)
|
||||
..setNewDetails(
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2022, 1, 1), DatePrecision.day, 'US')
|
||||
],
|
||||
);
|
||||
expect(movie1.same(movie2), isFalse);
|
||||
});
|
||||
test('can be encoded to JSON and back', () {
|
||||
final movie = MovieData(
|
||||
'Title 1',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
|
||||
movie.setDetails(releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')
|
||||
], genres: [
|
||||
'Action',
|
||||
'Adventure'
|
||||
], titles: [
|
||||
(title: 'Title 2', language: 'en')
|
||||
]);
|
||||
final movie = MovieData()
|
||||
..updateWithNewIgnoringUserControlled(firstMovie)
|
||||
..setNewDetails(
|
||||
genres: ['Action', 'Adventure'],
|
||||
);
|
||||
final json = movie.toJsonEncodable();
|
||||
final movie2 = MovieData.fromJsonEncodable(json);
|
||||
expect(movie2.title, equals('Title 1'));
|
||||
expect(movie2.releaseDate.country, equals('US'));
|
||||
expect(movie2.releaseDates!.length, equals(1));
|
||||
expect(movie2.releaseDates![0].country, equals('US'));
|
||||
expect(movie2.genres!.length, equals(2));
|
||||
expect(movie2.genres![0], equals('Action'));
|
||||
expect(movie2.genres![1], equals('Adventure'));
|
||||
expect(movie2.titles!.length, equals(1));
|
||||
expect(movie2.titles![0].title, equals('Title 2'));
|
||||
expect(movie2.titles![0].language, equals('en'));
|
||||
expect(movie2.releaseDate?.country, equals('US'));
|
||||
expect(movie2.releaseDates?.value?.length, equals(1));
|
||||
expect(movie2.releaseDates?.value?[0].country, equals('US'));
|
||||
expect(movie2.genres?.value?.length, equals(2));
|
||||
expect(movie2.genres?.value?[0], equals('Action'));
|
||||
expect(movie2.genres?.value?[1], equals('Adventure'));
|
||||
expect(movie2.titles, equals(null));
|
||||
});
|
||||
|
||||
test('toString()', () {
|
||||
final movie = MovieData(
|
||||
'Title 1',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'));
|
||||
movie.setDetails(releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')
|
||||
], genres: [
|
||||
'Action',
|
||||
'Adventure'
|
||||
], titles: [
|
||||
(title: 'Title 2', language: 'en')
|
||||
]);
|
||||
final movie = MovieData()
|
||||
..updateWithNewIgnoringUserControlled(firstMovie)
|
||||
..setNewDetails(
|
||||
genres: ['Action', 'Adventure'],
|
||||
);
|
||||
expect(movie.toString(),
|
||||
equals('Title 1 (January 1, 2023 (US); Action, Adventure)'));
|
||||
});
|
||||
|
|
|
@ -15,21 +15,30 @@ void main() {
|
|||
setUp(() {
|
||||
storage = InMemoryMovieStorage();
|
||||
storage.update([
|
||||
MovieData(
|
||||
'The Shawshank Redemption',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1994, 9, 22), DatePrecision.day, 'US'),
|
||||
),
|
||||
MovieData(
|
||||
'The Godfather',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1972, 3, 24), DatePrecision.day, 'US'),
|
||||
),
|
||||
MovieData(
|
||||
'The Dark Knight',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2008, 7, 18), DatePrecision.day, 'US'),
|
||||
),
|
||||
MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'The Shawshank Redemption', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1994, 9, 22), DatePrecision.day, 'US')
|
||||
],
|
||||
),
|
||||
MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'The Godfather', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1972, 3, 24), DatePrecision.day, 'US')
|
||||
],
|
||||
),
|
||||
MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'The Dark Knight', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2008, 7, 18), DatePrecision.day, 'US')
|
||||
],
|
||||
),
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
@ -6,20 +6,26 @@ import 'package:release_schedule/view/movie_item.dart';
|
|||
import 'package:release_schedule/view/movie_page.dart';
|
||||
|
||||
void main() {
|
||||
late MovieData testMovie;
|
||||
|
||||
setUp(() {
|
||||
testMovie = MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'Test Movie', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')
|
||||
],
|
||||
);
|
||||
});
|
||||
testWidgets('MovieItem displays movie data', (WidgetTester tester) async {
|
||||
final movie = MovieData(
|
||||
'Test Movie',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'),
|
||||
);
|
||||
movie.setDetails(
|
||||
testMovie.setNewDetails(
|
||||
genres: ['Action', 'Adventure'],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MovieItem(movie),
|
||||
body: MovieItem(testMovie),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -30,26 +36,17 @@ void main() {
|
|||
});
|
||||
|
||||
testWidgets('should update when the movie is modified', (tester) async {
|
||||
final movie = MovieData(
|
||||
'Test Movie',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'),
|
||||
);
|
||||
movie.setDetails(
|
||||
genres: ['Action', 'Adventure'],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MovieItem(movie),
|
||||
body: MovieItem(testMovie),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text('Test Movie'), findsOneWidget);
|
||||
|
||||
movie.setDetails(
|
||||
testMovie.setNewDetails(
|
||||
genres: ['Action', 'Adventure', 'Comedy'],
|
||||
);
|
||||
|
||||
|
@ -59,26 +56,17 @@ void main() {
|
|||
});
|
||||
|
||||
testWidgets('should update when the movie is bookmarked', (tester) async {
|
||||
final movie = MovieData(
|
||||
'Test Movie',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'),
|
||||
);
|
||||
movie.setDetails(
|
||||
genres: ['Action', 'Adventure'],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MovieItem(movie),
|
||||
body: MovieItem(testMovie),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byIcon(Icons.bookmark_border), findsOneWidget);
|
||||
|
||||
movie.setDetails(
|
||||
testMovie.setDetails(
|
||||
bookmarked: true,
|
||||
);
|
||||
|
||||
|
@ -89,19 +77,10 @@ void main() {
|
|||
|
||||
testWidgets("should update the bookmark state when the icon is tapped",
|
||||
(tester) async {
|
||||
final movie = MovieData(
|
||||
'Test Movie',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'),
|
||||
);
|
||||
movie.setDetails(
|
||||
genres: ['Action', 'Adventure'],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MovieItem(movie),
|
||||
body: MovieItem(testMovie),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -116,19 +95,10 @@ void main() {
|
|||
});
|
||||
|
||||
testWidgets("should navigate to MoviePage when tapped", (tester) async {
|
||||
final movie = MovieData(
|
||||
'Test Movie',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US'),
|
||||
);
|
||||
movie.setDetails(
|
||||
genres: ['Action', 'Adventure'],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MovieItem(movie),
|
||||
body: MovieItem(testMovie),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -7,20 +7,30 @@ import 'package:release_schedule/view/movie_list.dart';
|
|||
|
||||
void main() {
|
||||
group('MovieList', () {
|
||||
testWidgets('should render a list of movies', (WidgetTester tester) async {
|
||||
final movies = [
|
||||
MovieData(
|
||||
'The Shawshank Redemption',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1994, 9, 22), DatePrecision.day, 'US'),
|
||||
),
|
||||
MovieData(
|
||||
'The Godfather',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1972, 3, 24), DatePrecision.day, 'US'),
|
||||
),
|
||||
];
|
||||
late List<MovieData> movies;
|
||||
|
||||
setUp(() {
|
||||
movies = [
|
||||
MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'The Shawshank Redemption', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1994, 9, 22), DatePrecision.day, 'US')
|
||||
],
|
||||
),
|
||||
MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'The Godfather', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1972, 3, 24), DatePrecision.day, 'US')
|
||||
],
|
||||
)
|
||||
];
|
||||
});
|
||||
|
||||
testWidgets('should render a list of movies', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
|
@ -36,25 +46,12 @@ void main() {
|
|||
|
||||
testWidgets("should filter the list of movies",
|
||||
(WidgetTester tester) async {
|
||||
final movies = [
|
||||
MovieData(
|
||||
'The Shawshank Redemption',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1994, 9, 22), DatePrecision.day, 'US'),
|
||||
),
|
||||
MovieData(
|
||||
'The Godfather',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1972, 3, 24), DatePrecision.day, 'US'),
|
||||
),
|
||||
];
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MovieList(
|
||||
movies,
|
||||
filter: (movie) => movie.title.contains('Godfather'),
|
||||
filter: (movie) => movie.title?.contains('Godfather') == true,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -11,18 +11,31 @@ import 'package:release_schedule/view/movie_manager_list.dart';
|
|||
|
||||
void main() {
|
||||
group('MovieManagerList', () {
|
||||
late List<MovieData> movies;
|
||||
|
||||
setUp(() {
|
||||
movies = [
|
||||
MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'Movie 1', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')
|
||||
],
|
||||
),
|
||||
MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'Movie 2', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')
|
||||
],
|
||||
)
|
||||
];
|
||||
});
|
||||
testWidgets('displays movie list', (tester) async {
|
||||
final manager = MovieManager(MovieApi(), InMemoryMovieStorage());
|
||||
manager.addMovies([
|
||||
MovieData(
|
||||
'Movie 1',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')),
|
||||
MovieData(
|
||||
'Movie 2',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')),
|
||||
]);
|
||||
manager.addMovies(movies);
|
||||
// pump the delay until the change is written to the cache, so no timers run when the test finishes
|
||||
await tester.pump(const Duration(seconds: 5));
|
||||
|
||||
|
@ -35,25 +48,20 @@ void main() {
|
|||
|
||||
testWidgets('updates when new movies are added', (tester) async {
|
||||
final manager = MovieManager(MovieApi(), InMemoryMovieStorage());
|
||||
manager.addMovies([
|
||||
MovieData(
|
||||
'Movie 1',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')),
|
||||
MovieData(
|
||||
'Movie 2',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')),
|
||||
]);
|
||||
manager.addMovies(movies);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: MovieManagerList(manager))));
|
||||
|
||||
manager.addMovies([
|
||||
MovieData(
|
||||
'Movie 3',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')),
|
||||
MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'Movie 3', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(2023, 1, 1), DatePrecision.day, 'US')
|
||||
],
|
||||
)
|
||||
]);
|
||||
// pump the delay until the change is written to the cache, so no timers run when the test finishes
|
||||
await tester.pump(const Duration(seconds: 5));
|
||||
|
|
|
@ -6,13 +6,20 @@ import 'package:release_schedule/view/movie_page.dart';
|
|||
|
||||
void main() {
|
||||
group('MoviePage', () {
|
||||
testWidgets('should render the movie details', (WidgetTester tester) async {
|
||||
final movie = MovieData(
|
||||
'The Shawshank Redemption',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1994, 9, 22), DatePrecision.day, 'US'),
|
||||
);
|
||||
late MovieData movie;
|
||||
|
||||
setUp(() {
|
||||
movie = MovieData()
|
||||
..setNewDetails(
|
||||
labels: [(text: 'The Shawshank Redemption', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1994, 9, 22), DatePrecision.day, 'US')
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('should render the movie details', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
|
@ -23,16 +30,10 @@ void main() {
|
|||
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text(movie.title), findsAtLeastNWidgets(1));
|
||||
expect(find.text(movie.title!), findsAtLeastNWidgets(1));
|
||||
});
|
||||
|
||||
testWidgets('should bookmark the movie', (WidgetTester tester) async {
|
||||
final movie = MovieData(
|
||||
'The Shawshank Redemption',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1994, 9, 22), DatePrecision.day, 'US'),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
|
@ -50,56 +51,48 @@ void main() {
|
|||
|
||||
expect(movie.bookmarked, isTrue);
|
||||
});
|
||||
});
|
||||
testWidgets("should display the movie's genres",
|
||||
(WidgetTester tester) async {
|
||||
movie.setNewDetails(genres: ['Drama']);
|
||||
|
||||
testWidgets("should display the movie's genres", (WidgetTester tester) async {
|
||||
final movie = MovieData(
|
||||
'The Shawshank Redemption',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1994, 9, 22), DatePrecision.day, 'US'),
|
||||
)..setDetails(genres: ['Drama']);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MoviePage(movie),
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MoviePage(movie),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Drama'), findsOneWidget);
|
||||
});
|
||||
expect(find.text('Drama'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets("should display the movie's titles and release dates",
|
||||
(WidgetTester tester) async {
|
||||
final movie = MovieData(
|
||||
'The Shawshank Redemption',
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1994, 9, 22), DatePrecision.day, 'US'),
|
||||
)..setDetails(
|
||||
titles: [(title: 'The Shawshank Redemption', language: 'en')],
|
||||
testWidgets("should display the movie's titles and release dates",
|
||||
(WidgetTester tester) async {
|
||||
movie.setNewDetails(
|
||||
titles: [(text: 'The Shawshank Redemption', language: 'en')],
|
||||
releaseDates: [
|
||||
DateWithPrecisionAndCountry(
|
||||
DateTime(1994, 9, 22), DatePrecision.day, 'US')
|
||||
],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MoviePage(movie),
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MoviePage(movie),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('en'), findsOneWidget);
|
||||
expect(find.text('The Shawshank Redemption'), findsNWidgets(2));
|
||||
expect(find.text('en'), findsOneWidget);
|
||||
expect(find.text('The Shawshank Redemption'), findsNWidgets(2));
|
||||
|
||||
expect(find.text('US'), findsOneWidget);
|
||||
expect(find.textContaining('1994'), findsOneWidget);
|
||||
expect(find.text('US'), findsOneWidget);
|
||||
expect(find.textContaining('1994'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue