info: landscape layout
This commit is contained in:
parent
d919cd6022
commit
42820b7e48
4 changed files with 127 additions and 46 deletions
40
lib/widgets/fullscreen/info/basic_section.dart
Normal file
40
lib/widgets/fullscreen/info/basic_section.dart
Normal file
|
@ -0,0 +1,40 @@
|
|||
import 'package:aves/model/image_entry.dart';
|
||||
import 'package:aves/utils/file_utils.dart';
|
||||
import 'package:aves/widgets/fullscreen/info/info_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class BasicSection extends StatelessWidget {
|
||||
final ImageEntry entry;
|
||||
|
||||
const BasicSection({
|
||||
Key key,
|
||||
@required this.entry,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final date = entry.bestDate;
|
||||
final dateText = '${DateFormat.yMMMd().format(date)} – ${DateFormat.Hm().format(date)}';
|
||||
final resolutionText = '${entry.width} × ${entry.height}${entry.isVideo ? '' : ' (${entry.megaPixels} MP)'}';
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
InfoRow('Title', entry.title),
|
||||
InfoRow('Date', dateText),
|
||||
if (entry.isVideo) ..._buildVideoRows(),
|
||||
InfoRow('Resolution', resolutionText),
|
||||
InfoRow('Size', formatFilesize(entry.sizeBytes)),
|
||||
InfoRow('Uri', entry.uri),
|
||||
InfoRow('Path', entry.path),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildVideoRows() {
|
||||
final rotation = entry.catalogMetadata?.videoRotation;
|
||||
if (rotation != null) InfoRow('Rotation', '$rotation°');
|
||||
return [InfoRow('Duration', entry.durationText), if (rotation != null) InfoRow('Rotation', '$rotation°')];
|
||||
}
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
import 'package:aves/model/image_collection.dart';
|
||||
import 'package:aves/model/image_entry.dart';
|
||||
import 'package:aves/utils/file_utils.dart';
|
||||
import 'package:aves/widgets/fullscreen/info/basic_section.dart';
|
||||
import 'package:aves/widgets/fullscreen/info/location_section.dart';
|
||||
import 'package:aves/widgets/fullscreen/info/metadata_section.dart';
|
||||
import 'package:aves/widgets/fullscreen/info/xmp_section.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class InfoPage extends StatefulWidget {
|
||||
final ImageCollection collection;
|
||||
|
@ -34,9 +33,8 @@ class InfoPageState extends State<InfoPage> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final date = entry.bestDate;
|
||||
final dateText = '${DateFormat.yMMMd().format(date)} – ${DateFormat.Hm().format(date)}';
|
||||
final resolutionText = '${entry.width} × ${entry.height}${entry.isVideo ? '' : ' (${entry.megaPixels} MP)'}';
|
||||
// use MediaQuery instead of unreliable OrientationBuilder
|
||||
final orientation = MediaQuery.of(context).orientation;
|
||||
final bottomInsets = MediaQuery.of(context).viewInsets.bottom;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
|
@ -53,14 +51,19 @@ class InfoPageState extends State<InfoPage> {
|
|||
child: ListView(
|
||||
padding: EdgeInsets.all(8.0) + EdgeInsets.only(bottom: bottomInsets),
|
||||
children: [
|
||||
InfoRow('Title', entry.title),
|
||||
InfoRow('Date', dateText),
|
||||
if (entry.isVideo) ..._buildVideoRows(),
|
||||
InfoRow('Resolution', resolutionText),
|
||||
InfoRow('Size', formatFilesize(entry.sizeBytes)),
|
||||
InfoRow('Path', entry.path),
|
||||
InfoRow('Uri', entry.uri),
|
||||
LocationSection(entry: entry),
|
||||
if (orientation == Orientation.landscape && entry.hasGps)
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: BasicSection(entry: entry)),
|
||||
SizedBox(width: 8),
|
||||
Expanded(child: LocationSection(entry: entry, showTitle: false)),
|
||||
],
|
||||
)
|
||||
else ...[
|
||||
BasicSection(entry: entry),
|
||||
LocationSection(entry: entry, showTitle: true),
|
||||
],
|
||||
XmpTagSection(collection: widget.collection, entry: entry),
|
||||
MetadataSection(entry: entry),
|
||||
],
|
||||
|
@ -71,12 +74,6 @@ class InfoPageState extends State<InfoPage> {
|
|||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildVideoRows() {
|
||||
final rotation = entry.catalogMetadata?.videoRotation;
|
||||
if (rotation != null) InfoRow('Rotation', '$rotation°');
|
||||
return [InfoRow('Duration', entry.durationText), if (rotation != null) InfoRow('Rotation', '$rotation°')];
|
||||
}
|
||||
|
||||
bool _handleTopScroll(Notification notification) {
|
||||
if (notification is ScrollNotification) {
|
||||
if (notification is ScrollStartNotification) {
|
||||
|
|
|
@ -7,8 +7,13 @@ import 'package:google_maps_flutter/google_maps_flutter.dart';
|
|||
|
||||
class LocationSection extends AnimatedWidget {
|
||||
final ImageEntry entry;
|
||||
final showTitle;
|
||||
|
||||
const LocationSection({Key key, this.entry}) : super(key: key, listenable: entry);
|
||||
const LocationSection({
|
||||
Key key,
|
||||
@required this.entry,
|
||||
@required this.showTitle,
|
||||
}) : super(key: key, listenable: entry);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -17,8 +22,11 @@ class LocationSection extends AnimatedWidget {
|
|||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SectionRow('Location'),
|
||||
SizedBox(height: 8),
|
||||
if (showTitle)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 8),
|
||||
child: SectionRow('Location'),
|
||||
),
|
||||
ImageMap(
|
||||
markerId: entry.path,
|
||||
latLng: LatLng(
|
||||
|
|
|
@ -44,36 +44,72 @@ class MetadataSectionState extends State<MetadataSection> {
|
|||
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
||||
final metadataMap = snapshot.data.cast<String, Map>();
|
||||
final directoryNames = metadataMap.keys.toList()..sort();
|
||||
|
||||
Widget content;
|
||||
// use MediaQuery instead of unreliable OrientationBuilder
|
||||
final orientation = MediaQuery.of(context).orientation;
|
||||
if (orientation == Orientation.landscape) {
|
||||
final threshold = directoryNames.map((k) => metadataMap[k].length).reduce((v, e) => v + e) / 2;
|
||||
final first = <String>[], second = <String>[];
|
||||
var processed = 0;
|
||||
for (int i = 0; i < directoryNames.length; i++) {
|
||||
final directoryName = directoryNames[i];
|
||||
if (processed <= threshold)
|
||||
first.add(directoryName);
|
||||
else
|
||||
second.add(directoryName);
|
||||
processed += 1 + metadataMap[directoryName].length;
|
||||
}
|
||||
debugPrint('first=$first second=$second');
|
||||
content = Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: getMetadataColumn(metadataMap, first)),
|
||||
SizedBox(width: 8),
|
||||
Expanded(child: getMetadataColumn(metadataMap, second)),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
content = getMetadataColumn(metadataMap, directoryNames);
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SectionRow('Metadata'),
|
||||
...directoryNames.expand(
|
||||
(directoryName) {
|
||||
final directory = metadataMap[directoryName];
|
||||
final tagKeys = directory.keys.toList()..sort();
|
||||
return [
|
||||
if (directoryName.isNotEmpty)
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: Text(directoryName,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Concourse Caps',
|
||||
)),
|
||||
),
|
||||
...tagKeys.map((tagKey) {
|
||||
final value = directory[tagKey] as String;
|
||||
if (value == null || value.isEmpty) return SizedBox.shrink();
|
||||
return InfoRow(tagKey, value.length > maxValueLength ? '${value.substring(0, maxValueLength)}…' : value);
|
||||
}),
|
||||
SizedBox(height: 16),
|
||||
];
|
||||
},
|
||||
)
|
||||
content,
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget getMetadataColumn(Map<String, Map> metadataMap, List<String> directoryNames) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
...directoryNames.expand((directoryName) {
|
||||
final directory = metadataMap[directoryName];
|
||||
final tagKeys = directory.keys.toList()..sort();
|
||||
return [
|
||||
if (directoryName.isNotEmpty)
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: Text(directoryName,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Concourse Caps',
|
||||
)),
|
||||
),
|
||||
...tagKeys.map((tagKey) {
|
||||
final value = directory[tagKey] as String;
|
||||
if (value == null || value.isEmpty) return SizedBox.shrink();
|
||||
return InfoRow(tagKey, value.length > maxValueLength ? '${value.substring(0, maxValueLength)}…' : value);
|
||||
}),
|
||||
SizedBox(height: 16),
|
||||
];
|
||||
}),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue