video: fixed aspect ratio, handle thumbnail loading error

This commit is contained in:
Thibault Deckers 2019-08-04 17:49:05 +09:00
parent cc0283d393
commit a7f9163ec3
6 changed files with 30 additions and 33 deletions

View file

@ -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) {

View file

@ -55,7 +55,7 @@ class ThumbnailState extends State<Thumbnail> {
@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<Thumbnail> {
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)
],
),
);

View file

@ -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

View file

@ -213,15 +213,9 @@ class ImagePageState extends State<ImagePage> 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<AvesVideo> {
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,
);
}

View file

@ -37,9 +37,9 @@ class InfoPageState extends State<InfoPage> {
@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<InfoPage> {
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),

View file

@ -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: [