From addb3e523618751daffc8901b1498e812c9ff2a8 Mon Sep 17 00:00:00 2001 From: Herwig Birke Date: Tue, 19 Nov 2024 17:28:42 +0100 Subject: [PATCH] Movie Search --- lib/widgets/movies/add/add_screen.dart | 202 ++++++++++++++++++ lib/widgets/movies/add/movie_search_list.dart | 64 ++++++ lib/widgets/movies/list_screen.dart | 15 +- pubspec.lock | 52 ++++- pubspec.yaml | 3 +- 5 files changed, 316 insertions(+), 20 deletions(-) create mode 100644 lib/widgets/movies/add/add_screen.dart create mode 100644 lib/widgets/movies/add/movie_search_list.dart diff --git a/lib/widgets/movies/add/add_screen.dart b/lib/widgets/movies/add/add_screen.dart new file mode 100644 index 0000000..ff01bb5 --- /dev/null +++ b/lib/widgets/movies/add/add_screen.dart @@ -0,0 +1,202 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; + +import 'package:logger/logger.dart'; +import 'package:multimedia/data/movies.dart'; +import 'package:multimedia/log_printer.dart'; +import 'package:multimedia/widgets/movies/add/movie_search_list.dart'; + +import 'package:tmdb_api/tmdb_api.dart' as TMDB; + +// ignore: must_be_immutable +class AddMovieScreen extends StatefulWidget { + AddMovieScreen({ + super.key, + }); + + @override + State createState() => _AddMovieScreenState(); +} + +class _AddMovieScreenState extends State { + Logger logger = getLogger(); + + String movieTitleSearch = ''; + + String yearSearch = ''; + + List movieList = []; + + late MovieSearchList movieSearchList; + + @override + Widget build(BuildContext context) { + movieSearchList = MovieSearchList(movieList: movieList); + + return Scaffold( + appBar: AppBar( + title: Text('Search Movie'), + actions: [ + Row( + children: [ + SizedBox( + width: 250, + child: TextField( + style: TextStyle(color: Colors.white), + decoration: InputDecoration( + labelText: 'Movie Title', + ), + onChanged: (text) { + movieTitleSearch = text; + }, + ), + ), + const SizedBox( + width: 10, + ), + SizedBox( + width: 50, + child: TextField( + style: TextStyle(color: Colors.white), + decoration: InputDecoration( + labelText: 'Year', + ), + onChanged: (text) { + yearSearch = text; + }, + ), + ), + const SizedBox( + width: 10, + ), + ElevatedButton( + onPressed: () { + startSearch(); + }, + child: const Text('Search'), + ), + ], + ), + const VerticalDivider( + width: 10, + thickness: 3, + indent: 0, + endIndent: 0, + color: Colors.grey, + ), + IconButton( + icon: const Icon(Icons.check_circle_outline), + tooltip: 'Save changes', + onPressed: () { + // if (save()) { + // Navigator.pop(context, movieDetails); + // } + }, + ), + IconButton( + icon: const Icon(Icons.highlight_off), + tooltip: 'Revert changes', + onPressed: () { + // Navigator.pop(context, null); + }, + ), + ], + ), + body: MovieSearchList( + movieList: movieList, + ), + ); + } + + String parseString(dynamic data, String field) { + if (data[field].toString() == Null) { + return ''; + } + + return data[field].toString(); + } + + DateTime parseDate(dynamic data, String field) { + if (data[field].toString() == Null) { + return DateTime(1900, 1, 1); + } + return DateTime.parse(data[field].toString()); + } + + double parseDouble(dynamic data, String field) { + if (data[field] == Null) { + return 0.0; + } + return data[field]; + } + + int parseInt(dynamic data, String field) { + if (data[field] == Null) { + return 0; + } + + return data[field]; + } + + Future startSearch() async { + if (movieTitleSearch.isEmpty) { + return; + } + + int year = int.tryParse(yearSearch) ?? 0; + + logger.i('Wir suchen ...'); + final tmdb = TMDB.TMDB(TMDB.ApiKeys( + 'a33271b9e54cdcb9a80680eaf5522f1b', 'apiReadAccessTokenv4')); + + final response = await tmdb.v3.search.queryMovies( + movieTitleSearch, + year: year, + language: 'de', + ); + // logger.i(response); + // logger.i(response['page']); + // logger.i(response['results']); + List movies = response['results']; + + setState( + () { + movieList.clear(); + + for (int i = 0; i < movies.length; i++) { + dynamic movie = movies[i]; + + String movieTitle = parseString(movie, 'title'); + String originalTitle = parseString(movie, 'original_title'); + String overview = parseString(movie, 'overview'); + DateTime releaseDate = parseDate(movie, 'release_date'); + String backdropPath = parseString(movie, 'backdrop_path'); + double voteAverage = parseDouble(movie, 'vote_average'); + int voteCount = parseInt(movie, 'vote_count'); + + logger.i(backdropPath); + movieList.add(Movie( + movieID: -1, + movieTitle: movieTitle, + originalTitle: originalTitle, + overview: overview, + releaseDate: releaseDate, + state: 0, + resolution: '', + backdropPath: backdropPath, + languages: '', + productionCountries: '', + productionCompanies: '', + voteAverage: voteAverage, + voteCount: voteCount, + cast: '', + crew: '', + genre: '', + localPath: '', + )); + } + }, + ); + } +} diff --git a/lib/widgets/movies/add/movie_search_list.dart b/lib/widgets/movies/add/movie_search_list.dart new file mode 100644 index 0000000..4617ddd --- /dev/null +++ b/lib/widgets/movies/add/movie_search_list.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:multimedia/data/movies.dart'; + +import 'package:logger/logger.dart'; +import 'package:multimedia/log_printer.dart'; + +// ignore: must_be_immutable +class MovieSearchList extends StatefulWidget { + MovieSearchList({ + super.key, + required List this.movieList, + }); + + List movieList = []; + + @override + State createState() => _MovieSearchListState(); +} + +class _MovieSearchListState extends State { + Logger logger = getLogger(); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SingleChildScrollView( + child: Column( + children: widget.movieList + .map( + (movie) => Column(children: [ + Row( + children: [ + movie.backdropPath == 'null' + ? const SizedBox(width: 200) + : Image.network( + 'https://image.tmdb.org/t/p/w200${movie.backdropPath}'), + Expanded( + child: CheckboxListTile( + title: Text( + '${movie.movieTitle} (${movie.releaseDate.year})'), + subtitle: Text(movie.overview), + value: movie.state == 1, + onChanged: (bool? value) { + setState(() { + if (movie.state == 1) { + movie.state = 0; + } else { + movie.state = 1; + } + }); + }, + ), + ), + ], + ), + const Divider(height: 0), + ]), + ) + .toList(), + ), + ), + ); + } +} diff --git a/lib/widgets/movies/list_screen.dart b/lib/widgets/movies/list_screen.dart index 609d823..c0b523d 100644 --- a/lib/widgets/movies/list_screen.dart +++ b/lib/widgets/movies/list_screen.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'package:multimedia/widgets/movies/add/add_screen.dart'; import 'package:multimedia/widgets/movies/details/details_screen.dart'; import 'package:multimedia/widgets/movies/filter_box.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -284,14 +285,6 @@ class _MoviesScreenState extends State { // } }, ), - IconButton( - icon: const Icon(Icons.search_outlined), - tooltip: 'Search for movie', - onPressed: () { - searchMovie(); - // Navigator.pop(context, null); - }, - ), IconButton( icon: const Icon(Icons.update_outlined), tooltip: 'Update movie', @@ -349,7 +342,11 @@ class _MoviesScreenState extends State { } void addMovie() { - logger.i('add movie'); + final m = Navigator.push( + context, MaterialPageRoute(builder: (ctx) => AddMovieScreen())); + + if (m != null) { + } else {} } void searchMovie() { diff --git a/pubspec.lock b/pubspec.lock index cf21ea3..9ad4ac3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -41,6 +41,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + colorize: + dependency: transitive + description: + name: colorize + sha256: "584746cd6ba1cba0633b6720f494fe6f9601c4170f0666c1579d2aa2a61071ba" + url: "https://pub.dev" + source: hosted + version: "3.0.0" crypto: dependency: transitive description: @@ -57,6 +65,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dio: + dependency: transitive + description: + name: dio + sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" + url: "https://pub.dev" + source: hosted + version: "5.7.0" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" + url: "https://pub.dev" + source: hosted + version: "2.0.0" fake_async: dependency: transitive description: @@ -132,10 +156,10 @@ packages: dependency: "direct main" description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "99f282cb0e02edcbbf8c6b3bbc7c90b65635156c412e58f3975a7e55284ce685" url: "https://pub.dev" source: hosted - version: "0.19.0" + version: "0.20.0" leak_tracker: dependency: transitive description: @@ -172,10 +196,10 @@ packages: dependency: "direct main" description: name: logger - sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32" + sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1 url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.5.0" matcher: dependency: transitive description: @@ -369,18 +393,18 @@ packages: dependency: "direct main" description: name: syncfusion_flutter_core - sha256: "31d2ddf410ee41abb3ecf85b7b6e8e1563307ad52ee784ddd91337e30280f715" + sha256: "225b1cc135549bb4eef096d63b7323c30ee61c4b095c7e8a14bf9333e243d84b" url: "https://pub.dev" source: hosted - version: "27.1.58" + version: "27.2.2" syncfusion_flutter_datagrid: dependency: "direct main" description: name: syncfusion_flutter_datagrid - sha256: e7ddbb1bbadbb671e5fd636cadcde2ae06d9eec294c24937859f3c77ed1d1cbe + sha256: "6db8e5828dcc65f603a948cc28beb07c506654a4cf22a490924eb568c944d344" url: "https://pub.dev" source: hosted - version: "27.1.58" + version: "27.2.2" term_glyph: dependency: transitive description: @@ -397,6 +421,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.2" + tmdb_api: + dependency: "direct main" + description: + name: tmdb_api + sha256: d0db63d044dcc104731610b68f496d7a672dde70b5261f6272c8dfba2d4489d7 + url: "https://pub.dev" + source: hosted + version: "2.2.0" transparent_image: dependency: "direct main" description: @@ -433,10 +465,10 @@ packages: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "0.5.1" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f835490..4112271 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,12 +37,13 @@ dependencies: cupertino_icons: ^1.0.2 http: ^1.2.0 syncfusion_flutter_datagrid: ^27.1.58 - intl: ^0.19.0 + intl: ^0.20.0 syncfusion_flutter_core: ^27.1.58 google_fonts: ^6.2.1 shared_preferences: ^2.3.3 transparent_image: ^2.0.1 logger: ^2.4.0 + tmdb_api: ^2.2.0 dev_dependencies: