diff --git a/lib/model/image_entry.dart b/lib/model/image_entry.dart index c7cd93d3d..111c1044e 100644 --- a/lib/model/image_entry.dart +++ b/lib/model/image_entry.dart @@ -71,22 +71,22 @@ class ImageEntry { bool get isVideo => mimeType.startsWith(MimeTypes.MIME_VIDEO); - int getMegaPixels() { - return ((width * height) / 1000000).round(); - } + double get aspectRatio => height == 0 ? 1 : width / height; - DateTime getBestDate() { + int get megaPixels => (width * height / 1000000).round(); + + DateTime get bestDate { if (sourceDateTakenMillis != null && sourceDateTakenMillis > 0) return DateTime.fromMillisecondsSinceEpoch(sourceDateTakenMillis); if (dateModifiedSecs != null && dateModifiedSecs > 0) return DateTime.fromMillisecondsSinceEpoch(dateModifiedSecs * 1000); return null; } - DateTime getMonthTaken() { - final d = getBestDate(); + DateTime get monthTaken { + final d = bestDate; return d == null ? null : DateTime(d.year, d.month); } - String getDurationText() { + String get durationText { final d = Duration(milliseconds: durationMillis); String twoDigits(int n) { diff --git a/lib/thumbnail.dart b/lib/thumbnail.dart index c5de7bd9b..befe64f42 100644 --- a/lib/thumbnail.dart +++ b/lib/thumbnail.dart @@ -55,7 +55,7 @@ class ThumbnailState extends State { @override Widget build(BuildContext context) { - final fontSize = (widget.extent / 8).roundToDouble(); + final fontSize = min(14.0, (widget.extent / 8).roundToDouble()); final iconSize = fontSize * 2; return DefaultTextStyle( style: TextStyle( @@ -86,12 +86,14 @@ class ThumbnailState extends State { return Container( alignment: Alignment.center, constraints: BoxConstraints.tight(Size(dim, dim)), - child: Image.memory( - bytes, - width: dim, - height: dim, - fit: BoxFit.cover, - ), + child: bytes.length > 0 + ? Image.memory( + bytes, + width: dim, + height: dim, + fit: BoxFit.cover, + ) + : Icon(Icons.error), ); }), ), @@ -123,7 +125,7 @@ class VideoTag extends StatelessWidget { Widget build(BuildContext context) { return Container( margin: EdgeInsets.all(1), - padding: EdgeInsets.only(right: 4), + padding: EdgeInsets.only(right: iconSize / 4), decoration: BoxDecoration( color: Color(0xBB000000), borderRadius: BorderRadius.all( @@ -139,9 +141,7 @@ class VideoTag extends StatelessWidget { size: iconSize, ), SizedBox(width: 2), - Text( - entry.getDurationText(), - ) + Text(entry.durationText) ], ), ); diff --git a/lib/thumbnail_collection.dart b/lib/thumbnail_collection.dart index 2628d0751..a8a31bb93 100644 --- a/lib/thumbnail_collection.dart +++ b/lib/thumbnail_collection.dart @@ -16,7 +16,7 @@ class ThumbnailCollection extends StatelessWidget { final ScrollController scrollController = ScrollController(); ThumbnailCollection({Key key, this.entries, this.done}) - : sections = groupBy(entries, (entry) => entry.getMonthTaken()), + : sections = groupBy(entries, (entry) => entry.monthTaken), super(key: key); @override diff --git a/lib/widgets/fullscreen/image_page.dart b/lib/widgets/fullscreen/image_page.dart index 836178b14..edc63efae 100644 --- a/lib/widgets/fullscreen/image_page.dart +++ b/lib/widgets/fullscreen/image_page.dart @@ -213,15 +213,9 @@ class ImagePageState extends State with AutomaticKeepAliveClientMixin builder: (galleryContext, index) { final entry = widget.entries[index]; if (entry.isVideo) { - final screenSize = MediaQuery.of(galleryContext).size; - final videoAspectRatio = entry.width / entry.height; - final childWidth = min(screenSize.width, entry.width); - final childHeight = childWidth / videoAspectRatio; - debugPrint('ImagePageState video path=${entry.path} childWidth=$childWidth childHeight=$childHeight var=$videoAspectRatio car=${childWidth / childHeight}'); - return PhotoViewGalleryPageOptions.customChild( child: AvesVideo(entry: entry), - childSize: Size(childWidth, childHeight), + childSize: MediaQuery.of(galleryContext).size, // no heroTag because `Chewie` already internally builds one with the videoController minScale: PhotoViewComputedScale.contained, initialScale: PhotoViewComputedScale.contained, @@ -264,15 +258,18 @@ class AvesVideoState extends State { VideoPlayerController videoPlayerController; ChewieController chewieController; + ImageEntry get entry => widget.entry; + @override void initState() { super.initState(); videoPlayerController = VideoPlayerController.file( - File(widget.entry.path), - // ensure the first frame is shown after the video is initialized - )..initialize().then((_) => setState(() {})); + File(entry.path), + ); chewieController = ChewieController( videoPlayerController: videoPlayerController, + aspectRatio: entry.aspectRatio, + autoInitialize: true, ); } diff --git a/lib/widgets/fullscreen/info_page.dart b/lib/widgets/fullscreen/info_page.dart index deb3dd83b..ecf7bf1bd 100644 --- a/lib/widgets/fullscreen/info_page.dart +++ b/lib/widgets/fullscreen/info_page.dart @@ -37,9 +37,9 @@ class InfoPageState extends State { @override Widget build(BuildContext context) { - final date = entry.getBestDate(); + final date = entry.bestDate; final dateText = '${DateFormat.yMMMd().format(date)} – ${DateFormat.Hm().format(date)}'; - final resolutionText = '${entry.width} × ${entry.height}${entry.isVideo ? '' : ' (${entry.getMegaPixels()} MP)'}'; + final resolutionText = '${entry.width} × ${entry.height}${entry.isVideo ? '' : ' (${entry.megaPixels} MP)'}'; return Scaffold( appBar: AppBar( leading: IconButton( @@ -75,7 +75,7 @@ class InfoPageState extends State { SectionRow('File'), InfoRow('Title', entry.title), InfoRow('Date', dateText), - if (entry.isVideo) InfoRow('Duration', entry.getDurationText()), + if (entry.isVideo) InfoRow('Duration', entry.durationText), InfoRow('Resolution', resolutionText), InfoRow('Size', formatFilesize(entry.sizeBytes)), InfoRow('Path', entry.path), diff --git a/lib/widgets/fullscreen/overlay.dart b/lib/widgets/fullscreen/overlay.dart index 843b5bf88..16679bbb2 100644 --- a/lib/widgets/fullscreen/overlay.dart +++ b/lib/widgets/fullscreen/overlay.dart @@ -150,7 +150,7 @@ class _FullscreenBottomOverlayContent extends StatelessWidget { @override Widget build(BuildContext context) { final subRowWidth = min(400.0, maxWidth); - final date = entry.getBestDate(); + final date = entry.bestDate; return DefaultTextStyle( style: TextStyle( shadows: [