feature: add page for displaying a movie
fix: only load and show upcoming movies with at least month date precisionmain
parent
618f5d135b
commit
0ea9aef7be
|
@ -138,7 +138,7 @@ class WikidataMovieData extends MovieData {
|
|||
String country = _getCachedLabelForEntity(selectInJson<String>(dateClaim,
|
||||
"qualifiers.${WikidataProperties.placeOfPublication}.*.datavalue.value.id")
|
||||
.firstOrNull ??
|
||||
"no country");
|
||||
"unknown location");
|
||||
return DateWithPrecisionAndCountry(DateTime.parse(value["time"]),
|
||||
_precisionFromWikidata(value["precision"]), country);
|
||||
}).toList();
|
||||
|
@ -153,6 +153,7 @@ class WikidataMovieData extends MovieData {
|
|||
WikidataMovieData(title, releaseDates[0], entityId);
|
||||
movie.setDetails(
|
||||
titles: titles,
|
||||
releaseDates: releaseDates,
|
||||
genres: genres,
|
||||
);
|
||||
return movie;
|
||||
|
@ -168,7 +169,8 @@ SELECT
|
|||
WHERE {
|
||||
?movie wdt:P31 wd:Q11424; # Q11424 is the item for "film"
|
||||
wdt:P577 ?releaseDate. # P577 is the "publication date" property
|
||||
FILTER (xsd:date(?releaseDate) >= xsd:date("$date"^^xsd:dateTime))
|
||||
?movie p:P577/psv:P577 [wikibase:timePrecision ?precision].
|
||||
FILTER (xsd:date(?releaseDate) >= xsd:date("$date"^^xsd:dateTime) && ?precision >= 10)
|
||||
}
|
||||
GROUP BY ?movie
|
||||
ORDER BY ?minReleaseDate
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:release_schedule/api/movie_api.dart';
|
||||
import 'package:release_schedule/api/wikidata_movie_api.dart';
|
||||
import 'package:release_schedule/model/movie.dart';
|
||||
import 'package:release_schedule/model/movie_manager.dart';
|
||||
import 'package:release_schedule/view/movie_manager_list.dart';
|
||||
|
||||
|
@ -37,11 +38,7 @@ class HomePage extends StatelessWidget {
|
|||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Release Schedule"),
|
||||
actions: [
|
||||
FilledButton(
|
||||
onPressed: () => manager.removeMoviesWhere((movie) => true),
|
||||
child: const Icon(Icons.delete))
|
||||
],
|
||||
actions: [HamburgerMenu(manager)],
|
||||
),
|
||||
body: DefaultTabController(
|
||||
length: 2,
|
||||
|
@ -51,7 +48,12 @@ class HomePage extends StatelessWidget {
|
|||
child: TabBarView(
|
||||
children: [
|
||||
Scaffold(
|
||||
body: MovieManagerList(manager),
|
||||
body: MovieManagerList(
|
||||
manager,
|
||||
// Only show movies that have a release date with at least month precision
|
||||
filter: (movie) =>
|
||||
movie.releaseDate.precision >= DatePrecision.month,
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: const Icon(Icons.refresh),
|
||||
onPressed: () => manager.loadUpcomingMovies(),
|
||||
|
@ -71,3 +73,28 @@ class HomePage extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HamburgerMenu extends StatelessWidget {
|
||||
final MovieManager manager;
|
||||
const HamburgerMenu(this.manager, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PopupMenuButton(
|
||||
icon: const Icon(Icons.menu),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem(
|
||||
child: const Text("Remove all not bookmarked"),
|
||||
onTap: () =>
|
||||
manager.removeMoviesWhere((movie) => !movie.bookmarked),
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: const Text("Remove all"),
|
||||
onTap: () => manager.removeMoviesWhere((movie) => true),
|
||||
),
|
||||
];
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,6 +146,24 @@ class MovieData extends ChangeNotifier {
|
|||
|
||||
enum DatePrecision { decade, year, month, day, hour, minute }
|
||||
|
||||
extension DatePrecisionComparison on DatePrecision {
|
||||
bool operator <(DatePrecision other) {
|
||||
return index < other.index;
|
||||
}
|
||||
|
||||
bool operator <=(DatePrecision other) {
|
||||
return index <= other.index;
|
||||
}
|
||||
|
||||
bool operator >(DatePrecision other) {
|
||||
return index > other.index;
|
||||
}
|
||||
|
||||
bool operator >=(DatePrecision other) {
|
||||
return index >= other.index;
|
||||
}
|
||||
}
|
||||
|
||||
typedef TitleInLanguage = ({String title, String language});
|
||||
|
||||
class DateWithPrecisionAndCountry {
|
||||
|
@ -167,7 +185,11 @@ class DateWithPrecisionAndCountry {
|
|||
|
||||
@override
|
||||
String toString() {
|
||||
String dateString = switch (precision) {
|
||||
return "${toDateString()} ($country)";
|
||||
}
|
||||
|
||||
String toDateString() {
|
||||
return switch (precision) {
|
||||
DatePrecision.decade =>
|
||||
"${DateFormat("yyyy").format(date).substring(0, 3)}0s",
|
||||
DatePrecision.year => date.year.toString(),
|
||||
|
@ -176,7 +198,6 @@ class DateWithPrecisionAndCountry {
|
|||
DatePrecision.hour => DateFormat("MMMM d, yyyy, HH").format(date),
|
||||
DatePrecision.minute => DateFormat("MMMM d, yyyy, HH:mm").format(date)
|
||||
};
|
||||
return "$dateString ($country)";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:release_schedule/model/date_format.dart';
|
||||
import 'package:release_schedule/model/movie.dart';
|
||||
import 'package:release_schedule/view/movie_page.dart';
|
||||
|
||||
class MovieItem extends StatelessWidget {
|
||||
final MovieData movie;
|
||||
|
@ -21,6 +22,16 @@ class MovieItem extends StatelessWidget {
|
|||
: Icons.bookmark_border),
|
||||
onPressed: () => movie.setDetails(bookmarked: !movie.bookmarked),
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return MoviePage(movie);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:release_schedule/model/movie.dart';
|
||||
|
||||
class Heading extends StatelessWidget {
|
||||
final String text;
|
||||
|
||||
const Heading(this.text, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 20, bottom: 10),
|
||||
child: Text(
|
||||
text,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MoviePage extends StatelessWidget {
|
||||
final MovieData movie;
|
||||
|
||||
const MoviePage(this.movie, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: movie,
|
||||
builder: (context, child) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(movie.title),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Wrap(
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
children: movie.genres
|
||||
?.map((genre) => Chip(label: Text(genre)))
|
||||
.toList() ??
|
||||
[],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const Heading("Titles"),
|
||||
Table(
|
||||
border: TableBorder.symmetric(
|
||||
inside: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
),
|
||||
children: movie.titles?.map((title) {
|
||||
return TableRow(
|
||||
children: [
|
||||
TableCell(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(title.language),
|
||||
)),
|
||||
TableCell(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(title.title),
|
||||
))
|
||||
],
|
||||
);
|
||||
}).toList() ??
|
||||
[],
|
||||
),
|
||||
const Heading("Release Dates"),
|
||||
Table(
|
||||
border: TableBorder.symmetric(
|
||||
inside: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
),
|
||||
children: movie.releaseDates?.map((releaseDate) {
|
||||
return TableRow(
|
||||
children: [
|
||||
TableCell(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(releaseDate.country),
|
||||
)),
|
||||
TableCell(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(releaseDate.toDateString()),
|
||||
))
|
||||
],
|
||||
);
|
||||
}).toList() ??
|
||||
[],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue