info: back to image on top overscroll or button

This commit is contained in:
Thibault Deckers 2019-07-30 00:55:18 +09:00
parent 9c8df80a48
commit 8f94af28d3
3 changed files with 89 additions and 46 deletions

View file

@ -73,8 +73,20 @@ class FullscreenPageState extends State<FullscreenPage> with SingleTickerProvide
onPageChanged: (page) => setState(() => _currentHorizontalPage = page), onPageChanged: (page) => setState(() => _currentHorizontalPage = page),
onScaleChanged: (state) => setState(() => _isInitialScale = state == PhotoViewScaleState.initial), onScaleChanged: (state) => setState(() => _isInitialScale = state == PhotoViewScaleState.initial),
), ),
InfoPage( NotificationListener(
entry: entries[_currentHorizontalPage], onNotification: (notification) {
if (notification is BackUpNotification) {
_verticalPager.animateToPage(
0,
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
);
}
return false;
},
child: InfoPage(
entry: entries[_currentHorizontalPage],
),
), ),
], ],
), ),

View file

@ -15,6 +15,7 @@ class InfoPage extends StatefulWidget {
class InfoPageState extends State<InfoPage> { class InfoPageState extends State<InfoPage> {
Future<Map> _metadataLoader; Future<Map> _metadataLoader;
bool _scrollStartFromTop = false;
ImageEntry get entry => widget.entry; ImageEntry get entry => widget.entry;
@ -39,50 +40,74 @@ class InfoPageState extends State<InfoPage> {
final date = entry.getBestDate(); final date = entry.getBestDate();
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: () => BackUpNotification().dispatch(context),
tooltip: 'Back to image',
),
title: Text('Info'), title: Text('Info'),
), ),
body: ListView( body: NotificationListener(
padding: EdgeInsets.all(8.0), onNotification: (notification) {
children: [ if (notification is ScrollNotification) {
SectionRow('File'), if (notification is ScrollStartNotification) {
InfoRow('Title', entry.title), final metrics = notification.metrics;
InfoRow('Date', '${DateFormat.yMMMd().format(date)} ${DateFormat.Hm().format(date)}'), _scrollStartFromTop = metrics.pixels == metrics.minScrollExtent;
InfoRow('Resolution', '${entry.width} × ${entry.height} (${entry.getMegaPixels()} MP)'), }
InfoRow('Size', formatFilesize(entry.sizeBytes)), if (_scrollStartFromTop) {
InfoRow('Path', entry.path), if (notification is ScrollEndNotification) {
SectionRow('Location'), _scrollStartFromTop = false;
SectionRow('XMP Tags'), } else if (notification is OverscrollNotification) {
SectionRow('Metadata'), if (notification.overscroll < 0) {
FutureBuilder( BackUpNotification().dispatch(context);
future: _metadataLoader, _scrollStartFromTop = false;
builder: (futureContext, AsyncSnapshot<Map> snapshot) { }
if (snapshot.hasError) {
return Text(snapshot.error);
} }
if (snapshot.connectionState != ConnectionState.done) { }
return CircularProgressIndicator(); }
} return false;
final metadataMap = snapshot.data.cast<String, Map>(); },
final directoryNames = metadataMap.keys.toList()..sort(); child: ListView(
return Column( padding: EdgeInsets.all(8.0),
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: directoryNames.expand( SectionRow('File'),
(directoryName) { InfoRow('Title', entry.title),
final directory = metadataMap[directoryName]; InfoRow('Date', '${DateFormat.yMMMd().format(date)} ${DateFormat.Hm().format(date)}'),
final tagKeys = directory.keys.toList()..sort(); InfoRow('Resolution', '${entry.width} × ${entry.height} (${entry.getMegaPixels()} MP)'),
return [ InfoRow('Size', formatFilesize(entry.sizeBytes)),
Padding( InfoRow('Path', entry.path),
padding: EdgeInsets.symmetric(vertical: 4.0), SectionRow('Metadata'),
child: Text(directoryName, style: TextStyle(fontSize: 18)), FutureBuilder(
), future: _metadataLoader,
...tagKeys.map((tagKey) => InfoRow(tagKey, directory[tagKey])), builder: (futureContext, AsyncSnapshot<Map> snapshot) {
SizedBox(height: 16), if (snapshot.hasError) {
]; return Text(snapshot.error);
}, }
).toList()); if (snapshot.connectionState != ConnectionState.done) {
}, return CircularProgressIndicator();
), }
], final metadataMap = snapshot.data.cast<String, Map>();
final directoryNames = metadataMap.keys.toList()..sort();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: directoryNames.expand(
(directoryName) {
final directory = metadataMap[directoryName];
final tagKeys = directory.keys.toList()..sort();
return [
Padding(
padding: EdgeInsets.symmetric(vertical: 4.0),
child: Text(directoryName, style: TextStyle(fontSize: 18)),
),
...tagKeys.map((tagKey) => InfoRow(tagKey, directory[tagKey])),
SizedBox(height: 16),
];
},
).toList());
},
),
],
),
), ),
); );
} }
@ -96,7 +121,7 @@ class SectionRow extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: EdgeInsets.symmetric(vertical: 4.0), padding: EdgeInsets.symmetric(vertical: 8.0),
child: Row( child: Row(
children: [ children: [
Expanded(child: Divider(color: Colors.white70)), Expanded(child: Divider(color: Colors.white70)),
@ -131,3 +156,5 @@ class InfoRow extends StatelessWidget {
); );
} }
} }
class BackUpNotification extends Notification {}

View file

@ -2,8 +2,8 @@ import 'dart:math';
import 'dart:ui'; import 'dart:ui';
import 'package:aves/model/android_app_service.dart'; import 'package:aves/model/android_app_service.dart';
import 'package:aves/model/metadata_service.dart';
import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_entry.dart';
import 'package:aves/model/metadata_service.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
@ -43,7 +43,11 @@ class FullscreenTopOverlay extends StatelessWidget {
title: Text('${index + 1}/${entries.length}'), title: Text('${index + 1}/${entries.length}'),
actions: [ actions: [
// IconButton(icon: Icon(Icons.delete), onPressed: delete), // IconButton(icon: Icon(Icons.delete), onPressed: delete),
IconButton(icon: Icon(Icons.share), onPressed: share), IconButton(
icon: Icon(Icons.share),
onPressed: share,
tooltip: 'Share',
),
], ],
elevation: 0, elevation: 0,
backgroundColor: kOverlayBackground, backgroundColor: kOverlayBackground,