overlay: fixed partial shooting details, added layout change animation
This commit is contained in:
parent
02095dfb56
commit
6a8122e456
5 changed files with 75 additions and 29 deletions
|
@ -114,18 +114,18 @@ class OverlayMetadata {
|
|||
this.exposureTime,
|
||||
this.focalLength,
|
||||
this.iso,
|
||||
}) : aperture = aperture.replaceFirst('f', 'ƒ');
|
||||
}) : aperture = aperture?.replaceFirst('f', 'ƒ');
|
||||
|
||||
factory OverlayMetadata.fromMap(Map map) {
|
||||
return OverlayMetadata(
|
||||
aperture: map['aperture'] ?? '',
|
||||
exposureTime: map['exposureTime'] ?? '',
|
||||
focalLength: map['focalLength'] ?? '',
|
||||
iso: map['iso'] ?? '',
|
||||
aperture: map['aperture'],
|
||||
exposureTime: map['exposureTime'],
|
||||
focalLength: map['focalLength'],
|
||||
iso: map['iso'],
|
||||
);
|
||||
}
|
||||
|
||||
bool get isEmpty => aperture.isEmpty && exposureTime.isEmpty && focalLength.isEmpty && iso.isEmpty;
|
||||
bool get isEmpty => aperture == null && exposureTime == null && focalLength == null && iso == null;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
|
|
|
@ -18,7 +18,8 @@ class Constants {
|
|||
offset: Offset(0.5, 1.0),
|
||||
);
|
||||
|
||||
static const String unknown = 'unknown';
|
||||
static const String overlayUnknown = '—'; // em dash
|
||||
static const String infoUnknown = 'unknown';
|
||||
|
||||
static const pointNemo = Tuple2(-48.876667, -123.393333);
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ class Durations {
|
|||
// fullscreen animations
|
||||
static const fullscreenPageAnimation = Duration(milliseconds: 300);
|
||||
static const fullscreenOverlayAnimation = Duration(milliseconds: 200);
|
||||
static const fullscreenOverlayChangeAnimation = Duration(milliseconds: 150);
|
||||
|
||||
// info
|
||||
static const mapStyleSwitchAnimation = Duration(milliseconds: 300);
|
||||
|
|
|
@ -29,7 +29,7 @@ class BasicSection extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final date = entry.bestDate;
|
||||
final dateText = date != null ? '${DateFormat.yMMMd().format(date)} • ${DateFormat.Hm().format(date)}' : Constants.unknown;
|
||||
final dateText = date != null ? '${DateFormat.yMMMd().format(date)} • ${DateFormat.Hm().format(date)}' : Constants.infoUnknown;
|
||||
final showMegaPixels = entry.isPhoto && entry.megaPixels != null && entry.megaPixels > 0;
|
||||
final resolutionText = '${entry.resolutionText}${showMegaPixels ? ' (${entry.megaPixels} MP)' : ''}';
|
||||
|
||||
|
@ -37,12 +37,12 @@ class BasicSection extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
InfoRowGroup({
|
||||
'Title': entry.bestTitle ?? Constants.unknown,
|
||||
'Title': entry.bestTitle ?? Constants.infoUnknown,
|
||||
'Date': dateText,
|
||||
if (entry.isVideo) ..._buildVideoRows(),
|
||||
if (!entry.isSvg) 'Resolution': resolutionText,
|
||||
'Size': entry.sizeBytes != null ? formatFilesize(entry.sizeBytes) : Constants.unknown,
|
||||
'URI': entry.uri ?? Constants.unknown,
|
||||
'Size': entry.sizeBytes != null ? formatFilesize(entry.sizeBytes) : Constants.infoUnknown,
|
||||
'URI': entry.uri ?? Constants.infoUnknown,
|
||||
if (entry.path != null) 'Path': entry.path,
|
||||
}),
|
||||
_buildChips(),
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:aves/model/settings/coordinate_format.dart';
|
|||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/metadata_service.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
import 'package:aves/utils/durations.dart';
|
||||
import 'package:aves/widgets/common/fx/blurred.dart';
|
||||
import 'package:aves/widgets/common/icons.dart';
|
||||
import 'package:aves/widgets/fullscreen/overlay/common.dart';
|
||||
|
@ -150,25 +151,21 @@ class _FullscreenBottomOverlayContent extends AnimatedWidget {
|
|||
final positionTitle = [
|
||||
if (position != null) position,
|
||||
if (entry.bestTitle != null) entry.bestTitle,
|
||||
].join(' – ');
|
||||
].join(' — '); // em dash
|
||||
final hasShootingDetails = details != null && !details.isEmpty && settings.showOverlayShootingDetails;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (positionTitle.isNotEmpty) Text(positionTitle, strutStyle: Constants.overflowStrutStyle),
|
||||
if (entry.hasGps)
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: _interRowPadding),
|
||||
child: _LocationRow(entry: entry),
|
||||
),
|
||||
_buildSoloLocationRow(),
|
||||
if (twoColumns)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: _interRowPadding),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(width: subRowWidth, child: _DateRow(entry)),
|
||||
if (hasShootingDetails) Container(width: subRowWidth, child: _ShootingRow(details)),
|
||||
_buildDuoShootingRow(subRowWidth, hasShootingDetails),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
@ -178,12 +175,7 @@ class _FullscreenBottomOverlayContent extends AnimatedWidget {
|
|||
width: subRowWidth,
|
||||
child: _DateRow(entry),
|
||||
),
|
||||
if (hasShootingDetails)
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: _interRowPadding),
|
||||
width: subRowWidth,
|
||||
child: _ShootingRow(details),
|
||||
),
|
||||
_buildSoloShootingRow(subRowWidth, hasShootingDetails),
|
||||
],
|
||||
],
|
||||
);
|
||||
|
@ -192,6 +184,58 @@ class _FullscreenBottomOverlayContent extends AnimatedWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSoloLocationRow() => AnimatedSwitcher(
|
||||
duration: Durations.fullscreenOverlayChangeAnimation,
|
||||
switchInCurve: Curves.easeInOutCubic,
|
||||
switchOutCurve: Curves.easeInOutCubic,
|
||||
transitionBuilder: _soloTransition,
|
||||
child: entry.hasGps
|
||||
? Container(
|
||||
padding: EdgeInsets.only(top: _interRowPadding),
|
||||
child: _LocationRow(entry: entry),
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
);
|
||||
|
||||
Widget _buildSoloShootingRow(double subRowWidth, bool hasShootingDetails) => AnimatedSwitcher(
|
||||
duration: Durations.fullscreenOverlayChangeAnimation,
|
||||
switchInCurve: Curves.easeInOutCubic,
|
||||
switchOutCurve: Curves.easeInOutCubic,
|
||||
transitionBuilder: _soloTransition,
|
||||
child: hasShootingDetails
|
||||
? Container(
|
||||
padding: EdgeInsets.only(top: _interRowPadding),
|
||||
width: subRowWidth,
|
||||
child: _ShootingRow(details),
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
);
|
||||
|
||||
Widget _buildDuoShootingRow(double subRowWidth, bool hasShootingDetails) => AnimatedSwitcher(
|
||||
duration: Durations.fullscreenOverlayChangeAnimation,
|
||||
switchInCurve: Curves.easeInOutCubic,
|
||||
switchOutCurve: Curves.easeInOutCubic,
|
||||
transitionBuilder: (child, animation) => FadeTransition(
|
||||
opacity: animation,
|
||||
child: child,
|
||||
),
|
||||
child: hasShootingDetails
|
||||
? Container(
|
||||
width: subRowWidth,
|
||||
child: _ShootingRow(details),
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
);
|
||||
|
||||
static Widget _soloTransition(Widget child, Animation<double> animation) => FadeTransition(
|
||||
opacity: animation,
|
||||
child: SizeTransition(
|
||||
axisAlignment: 1,
|
||||
sizeFactor: animation,
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class _LocationRow extends AnimatedWidget {
|
||||
|
@ -228,7 +272,7 @@ class _DateRow extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final date = entry.bestDate;
|
||||
final dateText = date != null ? '${DateFormat.yMMMd().format(date)} • ${DateFormat.Hm().format(date)}' : Constants.unknown;
|
||||
final dateText = date != null ? '${DateFormat.yMMMd().format(date)} • ${DateFormat.Hm().format(date)}' : Constants.infoUnknown;
|
||||
return Row(
|
||||
children: [
|
||||
DecoratedIcon(AIcons.date, shadows: [Constants.embossShadow], size: _iconSize),
|
||||
|
@ -251,10 +295,10 @@ class _ShootingRow extends StatelessWidget {
|
|||
children: [
|
||||
DecoratedIcon(AIcons.shooting, shadows: [Constants.embossShadow], size: _iconSize),
|
||||
SizedBox(width: _iconPadding),
|
||||
Expanded(child: Text(details.aperture, strutStyle: Constants.overflowStrutStyle)),
|
||||
Expanded(child: Text(details.exposureTime, strutStyle: Constants.overflowStrutStyle)),
|
||||
Expanded(child: Text(details.focalLength, strutStyle: Constants.overflowStrutStyle)),
|
||||
Expanded(child: Text(details.iso, strutStyle: Constants.overflowStrutStyle)),
|
||||
Expanded(child: Text(details.aperture ?? Constants.overlayUnknown, strutStyle: Constants.overflowStrutStyle)),
|
||||
Expanded(child: Text(details.exposureTime ?? Constants.overlayUnknown, strutStyle: Constants.overflowStrutStyle)),
|
||||
Expanded(child: Text(details.focalLength ?? Constants.overlayUnknown, strutStyle: Constants.overflowStrutStyle)),
|
||||
Expanded(child: Text(details.iso ?? Constants.overlayUnknown, strutStyle: Constants.overflowStrutStyle)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue