release_schedule/lib/model/movie.dart

236 lines
7.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:release_schedule/model/dates.dart';
class MovieData extends ChangeNotifier {
bool _bookmarked = false;
String? _title;
DateWithPrecisionAndCountry? _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;
MovieData();
String? get title {
return _title;
}
DateWithPrecisionAndCountry? get releaseDate {
return _releaseDate;
}
bool get bookmarked {
return _bookmarked;
}
Dated<String?>? get description {
return _description;
}
Dated<List<DateWithPrecisionAndCountry>?>? get releaseDates {
return _releaseDates;
}
Dated<List<String>?>? get genres {
return _genres;
}
Dated<List<TextInLanguage>?>? get titles {
return _titles;
}
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(
titles: movie.titles,
labels: movie.labels,
releaseDates: movie.releaseDates,
genres: movie.genres,
description: movie.description,
);
}
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 (titles != null) {
_titles = titles;
}
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?.value?.isNotEmpty ?? false ? "; ${_genres?.value?.join(", ")}" : ""})";
}
bool same(MovieData other) {
return title != null &&
title == other.title &&
(releaseDate == null ||
other.releaseDate == null ||
releaseDate!.dateWithPrecision.date.year ==
other.releaseDate!.dateWithPrecision.date.year);
}
Map toJsonEncodable() {
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 {
"bookmarked": _bookmarked,
"titles": titlesByCountry,
"labels": labels,
"releaseDates": releaseDatesByCountry,
"genres": genres,
"description":
_description?.toJsonEncodable((description) => description),
};
}
MovieData.fromJsonEncodable(Map json) {
setDetails(
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)),
);
}
}
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;
final String country;
DateWithPrecisionAndCountry(
DateTime date, DatePrecision precision, this.country)
: dateWithPrecision = DateWithPrecision(date, precision);
DateWithPrecisionAndCountry.fromJsonEncodable(List<dynamic> json)
: dateWithPrecision = DateWithPrecision.fromJsonEncodable(json),
country = json[2];
toJsonEncodable() {
return dateWithPrecision.toJsonEncodable() + [country];
}
@override
String toString() {
return "${dateWithPrecision.toString()} ($country)";
}
}