From f132c3d5761b057bb5153dec37e6f7d9ed695198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asc=C3=AAnio=20Sanderson?= Date: Wed, 8 May 2024 19:58:58 -0300 Subject: [PATCH] feat: show thumbs of videos --- lib/core/date_formatters/date_formatter.dart | 9 ++++ .../http_remote_nasa_datasource.dart | 6 +-- .../sqflite_local_nasa_datasource.dart | 24 ++++------ ...load_picture_of_the_day_request_model.dart | 1 + .../data/models/local_picture_model.dart | 44 +++++++++++++++++++ ...e_model.dart => remote_picture_model.dart} | 14 +++--- .../widgets/image_or_video_widget.dart | 14 +++--- 7 files changed, 79 insertions(+), 33 deletions(-) create mode 100644 lib/core/date_formatters/date_formatter.dart create mode 100644 lib/features/picture_of_the_day/data/models/local_picture_model.dart rename lib/features/picture_of_the_day/data/models/{picture_model.dart => remote_picture_model.dart} (53%) diff --git a/lib/core/date_formatters/date_formatter.dart b/lib/core/date_formatters/date_formatter.dart new file mode 100644 index 0000000..98ef0ce --- /dev/null +++ b/lib/core/date_formatters/date_formatter.dart @@ -0,0 +1,9 @@ +import 'package:intl/intl.dart'; + +final class DateFormatter { + const DateFormatter._(); + + static final _yyyyMMddFormat = DateFormat('yyyy-MM-dd'); + + static String yyyyMMdd(DateTime date) => _yyyyMMddFormat.format(date); +} diff --git a/lib/features/picture_of_the_day/data/datasources/http_remote_nasa_datasource.dart b/lib/features/picture_of_the_day/data/datasources/http_remote_nasa_datasource.dart index fe6d7ec..efdd571 100644 --- a/lib/features/picture_of_the_day/data/datasources/http_remote_nasa_datasource.dart +++ b/lib/features/picture_of_the_day/data/datasources/http_remote_nasa_datasource.dart @@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; import 'package:nasa_potday/features/picture_of_the_day/data/datasources/remote_nasa_datasource.dart'; import 'package:nasa_potday/features/picture_of_the_day/data/models/load_picture_of_the_day_request_model.dart'; -import 'package:nasa_potday/features/picture_of_the_day/data/models/picture_model.dart'; +import 'package:nasa_potday/features/picture_of_the_day/data/models/remote_picture_model.dart'; import 'package:nasa_potday/features/picture_of_the_day/domain/entities/pictures_page_entity.dart'; final class HttpRemoteNasaDataSource implements RemoteNasaDataSource { @@ -42,7 +42,7 @@ final class HttpRemoteNasaDataSource implements RemoteNasaDataSource { ); } - Future> _request( + Future> _request( LoadPictureOfTheDayRequestModel request, ) async { final uri = Uri.parse(baseUrl).replace( @@ -51,7 +51,7 @@ final class HttpRemoteNasaDataSource implements RemoteNasaDataSource { final response = await get(uri); return (jsonDecode(response.body) as List) .cast>() - .map(PictureModel.fromJson) + .map(RemotePictureModel.fromJson) .toList() .reversed .toList(); diff --git a/lib/features/picture_of_the_day/data/datasources/sqflite_local_nasa_datasource.dart b/lib/features/picture_of_the_day/data/datasources/sqflite_local_nasa_datasource.dart index 85723d6..cf2c939 100644 --- a/lib/features/picture_of_the_day/data/datasources/sqflite_local_nasa_datasource.dart +++ b/lib/features/picture_of_the_day/data/datasources/sqflite_local_nasa_datasource.dart @@ -1,8 +1,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; +import 'package:nasa_potday/core/date_formatters/date_formatter.dart'; import 'package:nasa_potday/features/picture_of_the_day/data/datasources/local_nasa_datasource.dart'; -import 'package:nasa_potday/features/picture_of_the_day/data/models/picture_model.dart'; +import 'package:nasa_potday/features/picture_of_the_day/data/models/local_picture_model.dart'; import 'package:nasa_potday/features/picture_of_the_day/domain/entities/picture_entity.dart'; import 'package:nasa_potday/features/picture_of_the_day/domain/entities/pictures_page_entity.dart'; import 'package:sqflite/sqflite.dart'; @@ -22,7 +22,8 @@ CREATE TABLE $_picturesTable ( 'date' TEXT PRIMARY KEY, url TEXT, title TEXT, - explanation TEXT + explanation TEXT, + is_video INTEGER ) '''); }, @@ -30,8 +31,6 @@ CREATE TABLE $_picturesTable ( return database; } - String _dateString(DateTime date) => DateFormat('yyyy-MM-dd').format(date); - @override Future save(PicturesPageEntity page) async { try { @@ -40,12 +39,7 @@ CREATE TABLE $_picturesTable ( for (final picture in page.pictures) { database.insert( _picturesTable, - { - 'date': _dateString(picture.date), - 'url': picture.url.toString(), - 'title': picture.title, - 'explanation': picture.explanation, - }, + LocalPictureModel.fromEntity(picture).toJson(), conflictAlgorithm: ConflictAlgorithm.replace, ); } @@ -67,13 +61,13 @@ CREATE TABLE $_picturesTable ( where: 'DATE(date) BETWEEN ? AND ?', orderBy: 'DATE(date) DESC', whereArgs: [ - _dateString(startDate), - _dateString(endDate), + DateFormatter.yyyyMMdd(startDate), + DateFormatter.yyyyMMdd(endDate), ], ); return PicturesPageEntity( startDate: startDate, - pictures: pictures.map(PictureModel.fromJson).toList(), + pictures: pictures.map(LocalPictureModel.fromJson).toList(), ); } on DatabaseException catch (error) { debugPrint('Could not load page $startDate: $error'); @@ -96,7 +90,7 @@ CREATE TABLE $_picturesTable ( whereArgs: ['%$title%'], orderBy: 'DATE(date) DESC', ); - return result.map(PictureModel.fromJson).toList(); + return result.map(LocalPictureModel.fromJson).toList(); } on DatabaseException catch (error) { debugPrint('Could not search for "$title": $error'); } diff --git a/lib/features/picture_of_the_day/data/models/load_picture_of_the_day_request_model.dart b/lib/features/picture_of_the_day/data/models/load_picture_of_the_day_request_model.dart index 171f29b..5335a64 100644 --- a/lib/features/picture_of_the_day/data/models/load_picture_of_the_day_request_model.dart +++ b/lib/features/picture_of_the_day/data/models/load_picture_of_the_day_request_model.dart @@ -14,6 +14,7 @@ class LoadPictureOfTheDayRequestModel { 'api_key': apiKey, 'start_date': _dateToString(startDate), 'end_date': _dateToString(endDate), + 'thumbs': 'true', }; } diff --git a/lib/features/picture_of_the_day/data/models/local_picture_model.dart b/lib/features/picture_of_the_day/data/models/local_picture_model.dart new file mode 100644 index 0000000..ba49bde --- /dev/null +++ b/lib/features/picture_of_the_day/data/models/local_picture_model.dart @@ -0,0 +1,44 @@ +import 'package:nasa_potday/core/date_formatters/date_formatter.dart'; +import 'package:nasa_potday/features/picture_of_the_day/domain/entities/picture_entity.dart'; + +class LocalPictureModel extends PictureEntity { + const LocalPictureModel({ + required super.url, + required super.title, + required super.explanation, + required super.date, + required super.isVideo, + }); + + factory LocalPictureModel.fromEntity(PictureEntity entity) { + return LocalPictureModel( + url: entity.url, + title: entity.title, + explanation: entity.explanation, + date: entity.date, + isVideo: entity.isVideo, + ); + } + + Map toJson() { + return { + 'date': DateFormatter.yyyyMMdd(date), + 'url': url.toString(), + 'title': title, + 'explanation': explanation, + 'is_video': isVideo ? 1 : 0, + }; + } + + factory LocalPictureModel.fromJson(Map json) { + final isVideo = json['media_type'] == 'video'; + + return LocalPictureModel( + url: Uri.parse(isVideo ? json['thumbnail_url'] : json['url']), + title: json['title'], + explanation: json['explanation'], + date: DateTime.parse(json['date']), + isVideo: json['is_video'] == 1, + ); + } +} diff --git a/lib/features/picture_of_the_day/data/models/picture_model.dart b/lib/features/picture_of_the_day/data/models/remote_picture_model.dart similarity index 53% rename from lib/features/picture_of_the_day/data/models/picture_model.dart rename to lib/features/picture_of_the_day/data/models/remote_picture_model.dart index f2f9636..b503b80 100644 --- a/lib/features/picture_of_the_day/data/models/picture_model.dart +++ b/lib/features/picture_of_the_day/data/models/remote_picture_model.dart @@ -1,7 +1,7 @@ import 'package:nasa_potday/features/picture_of_the_day/domain/entities/picture_entity.dart'; -class PictureModel extends PictureEntity { - const PictureModel({ +class RemotePictureModel extends PictureEntity { + const RemotePictureModel({ required super.url, required super.title, required super.explanation, @@ -9,15 +9,15 @@ class PictureModel extends PictureEntity { required super.isVideo, }); - factory PictureModel.fromJson(Map json) { - final url = Uri.parse(json['url']); + factory RemotePictureModel.fromJson(Map json) { + final isVideo = json['media_type'] == 'video'; - return PictureModel( - url: url, + return RemotePictureModel( + url: Uri.parse(isVideo ? json['thumbnail_url'] : json['url']), title: json['title'], explanation: json['explanation'], date: DateTime.parse(json['date']), - isVideo: json['media_type'] == 'video', + isVideo: isVideo, ); } } diff --git a/lib/features/picture_of_the_day/presentation/widgets/image_or_video_widget.dart b/lib/features/picture_of_the_day/presentation/widgets/image_or_video_widget.dart index 0fddb02..95f272c 100644 --- a/lib/features/picture_of_the_day/presentation/widgets/image_or_video_widget.dart +++ b/lib/features/picture_of_the_day/presentation/widgets/image_or_video_widget.dart @@ -24,13 +24,9 @@ class ImageOrVideoWidget extends StatelessWidget { tag: url, child: SizedBox( height: size.height / 3, - child: switch (isVideo) { - true => Container( - width: double.infinity, - color: surfaceColor, - child: Image.asset('assets/youtube-logo.png'), - ), - false => CachedNetworkImage( + child: Stack( + children: [ + CachedNetworkImage( imageUrl: url.toString(), width: double.infinity, height: size.height / 3, @@ -73,7 +69,9 @@ class ImageOrVideoWidget extends StatelessWidget { ); }, ), - }, + if (isVideo) Center(child: Image.asset('assets/youtube-logo.png')), + ], + ), ), ); }