various minor fixes

This commit is contained in:
Thibault Deckers 2020-11-29 19:07:35 +09:00
parent 154ceecae0
commit 3ef5cde4da
7 changed files with 73 additions and 52 deletions

View file

@ -4,11 +4,13 @@ class XMP {
// cf https://exiftool.org/TagNames/XMP.html // cf https://exiftool.org/TagNames/XMP.html
static const Map<String, String> namespaces = { static const Map<String, String> namespaces = {
'aux': 'Auxiliary Exif', 'aux': 'Exif Aux',
'Camera': 'Camera', 'Camera': 'Camera',
'crs': 'Camera Raw Settings', 'crs': 'Camera Raw Settings',
'dc': 'Dublin Core', 'dc': 'Dublin Core',
'exif': 'Exif', 'exif': 'Exif',
'exifEX': 'Exif Ex',
'GettyImagesGIFT': 'Getty Images',
'GIMP': 'GIMP', 'GIMP': 'GIMP',
'illustrator': 'Illustrator', 'illustrator': 'Illustrator',
'Iptc4xmpCore': 'IPTC Core', 'Iptc4xmpCore': 'IPTC Core',
@ -19,6 +21,7 @@ class XMP {
'pdfx': 'PDF/X', 'pdfx': 'PDF/X',
'photomechanic': 'Photo Mechanic', 'photomechanic': 'Photo Mechanic',
'photoshop': 'Photoshop', 'photoshop': 'Photoshop',
'plus': 'PLUS',
'tiff': 'TIFF', 'tiff': 'TIFF',
'xmp': 'Basic', 'xmp': 'Basic',
'xmpBJ': 'Basic Job Ticket', 'xmpBJ': 'Basic Job Ticket',

View file

@ -87,6 +87,7 @@ class _LicensesState extends State<Licenses> {
Widget _buildHeader() { Widget _buildHeader() {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: EdgeInsetsDirectional.only(start: 8), padding: EdgeInsetsDirectional.only(start: 8),

View file

@ -3,7 +3,6 @@ import 'dart:math';
import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_entry.dart';
import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/widgets/collection/grid/header_generic.dart'; import 'package:aves/widgets/collection/grid/header_generic.dart';
import 'package:aves/widgets/collection/thumbnail_collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -15,14 +14,14 @@ class SectionedListLayoutProvider extends StatelessWidget {
final Widget Function(ImageEntry entry) thumbnailBuilder; final Widget Function(ImageEntry entry) thumbnailBuilder;
final Widget child; final Widget child;
SectionedListLayoutProvider({ const SectionedListLayoutProvider({
@required this.collection, @required this.collection,
@required this.scrollableWidth, @required this.scrollableWidth,
@required this.tileExtent, @required this.tileExtent,
@required this.columnCount,
@required this.thumbnailBuilder, @required this.thumbnailBuilder,
@required this.child, @required this.child,
}) : assert(scrollableWidth != 0), }) : assert(scrollableWidth != 0);
columnCount = max((scrollableWidth / tileExtent).round(), ThumbnailCollection.columnCountMin);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -31,9 +31,9 @@ class ThumbnailCollection extends StatelessWidget {
final ValueNotifier<bool> _isScrollingNotifier = ValueNotifier(false); final ValueNotifier<bool> _isScrollingNotifier = ValueNotifier(false);
final GlobalKey _scrollableKey = GlobalKey(); final GlobalKey _scrollableKey = GlobalKey();
static const columnCountMin = 2;
static const columnCountDefault = 4; static const columnCountDefault = 4;
static const extentMin = 46.0; static const extentMin = 46.0;
static const spacing = 0.0;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -47,11 +47,10 @@ class ThumbnailCollection extends StatelessWidget {
final tileExtentManager = TileExtentManager( final tileExtentManager = TileExtentManager(
settingsRouteKey: context.currentRouteName, settingsRouteKey: context.currentRouteName,
columnCountMin: columnCountMin, extentNotifier: _tileExtentNotifier,
columnCountDefault: columnCountDefault, columnCountDefault: columnCountDefault,
extentMin: extentMin, extentMin: extentMin,
extentNotifier: _tileExtentNotifier, spacing: spacing,
spacing: 0,
)..applyTileExtent(viewportSize: viewportSize); )..applyTileExtent(viewportSize: viewportSize);
final cacheExtent = tileExtentManager.getEffectiveExtentMax(viewportSize) * 2; final cacheExtent = tileExtentManager.getEffectiveExtentMax(viewportSize) * 2;
@ -77,7 +76,18 @@ class ThumbnailCollection extends StatelessWidget {
scrollableKey: _scrollableKey, scrollableKey: _scrollableKey,
appBarHeightNotifier: _appBarHeightNotifier, appBarHeightNotifier: _appBarHeightNotifier,
viewportSize: viewportSize, viewportSize: viewportSize,
showScaledGrid: true, gridBuilder: (center, extent, child) => CustomPaint(
// painting the thumbnail half-border on top of the grid yields artifacts,
// so we use a `foregroundPainter` to cover them instead
foregroundPainter: GridPainter(
center: center,
extent: extent,
spacing: tileExtentManager.spacing,
strokeWidth: DecoratedThumbnail.borderWidth * 2,
color: DecoratedThumbnail.borderColor,
),
child: child,
),
scaledBuilder: (entry, extent) => DecoratedThumbnail( scaledBuilder: (entry, extent) => DecoratedThumbnail(
entry: entry, entry: entry,
extent: extent, extent: extent,
@ -98,6 +108,7 @@ class ThumbnailCollection extends StatelessWidget {
collection: collection, collection: collection,
scrollableWidth: viewportSize.width, scrollableWidth: viewportSize.width,
tileExtent: tileExtent, tileExtent: tileExtent,
columnCount: tileExtentManager.getEffectiveColumnCountForExtent(viewportSize, tileExtent),
thumbnailBuilder: (entry) => GridThumbnail( thumbnailBuilder: (entry) => GridThumbnail(
key: ValueKey(entry.contentId), key: ValueKey(entry.contentId),
collection: collection, collection: collection,

View file

@ -2,7 +2,6 @@ import 'dart:math';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:aves/theme/durations.dart'; import 'package:aves/theme/durations.dart';
import 'package:aves/widgets/collection/thumbnail/decorated.dart';
import 'package:aves/widgets/common/providers/media_query_data_provider.dart'; import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
import 'package:aves/widgets/common/tile_extent_manager.dart'; import 'package:aves/widgets/common/tile_extent_manager.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -20,7 +19,7 @@ class GridScaleGestureDetector<T> extends StatefulWidget {
final GlobalKey scrollableKey; final GlobalKey scrollableKey;
final ValueNotifier<double> appBarHeightNotifier; final ValueNotifier<double> appBarHeightNotifier;
final Size viewportSize; final Size viewportSize;
final bool showScaledGrid; final Widget Function(Offset center, double extent, Widget child) gridBuilder;
final Widget Function(T item, double extent) scaledBuilder; final Widget Function(T item, double extent) scaledBuilder;
final Rect Function(BuildContext context, T item) getScaledItemTileRect; final Rect Function(BuildContext context, T item) getScaledItemTileRect;
final void Function(T item) onScaled; final void Function(T item) onScaled;
@ -31,7 +30,7 @@ class GridScaleGestureDetector<T> extends StatefulWidget {
@required this.scrollableKey, @required this.scrollableKey,
@required this.appBarHeightNotifier, @required this.appBarHeightNotifier,
@required this.viewportSize, @required this.viewportSize,
@required this.showScaledGrid, this.gridBuilder,
@required this.scaledBuilder, @required this.scaledBuilder,
@required this.getScaledItemTileRect, @required this.getScaledItemTileRect,
@required this.onScaled, @required this.onScaled,
@ -56,10 +55,6 @@ class _GridScaleGestureDetectorState<T> extends State<GridScaleGestureDetector<T
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
onHorizontalDragStart: (details) {
// if `onHorizontalDragStart` callback is not defined,
// horizontal drag gestures are interpreted as scaling
},
onScaleStart: (details) { onScaleStart: (details) {
// the gesture detector wrongly detects a new scaling gesture // the gesture detector wrongly detects a new scaling gesture
// when scaling ends and we apply the new extent, so we prevent this // when scaling ends and we apply the new extent, so we prevent this
@ -91,10 +86,9 @@ class _GridScaleGestureDetectorState<T> extends State<GridScaleGestureDetector<T
builder: (context) => ScaleOverlay( builder: (context) => ScaleOverlay(
builder: (extent) => widget.scaledBuilder(_metadata.item, extent), builder: (extent) => widget.scaledBuilder(_metadata.item, extent),
center: thumbnailCenter, center: thumbnailCenter,
gridWidth: gridWidth, viewportWidth: gridWidth,
spacing: tileExtentManager.spacing, gridBuilder: widget.gridBuilder,
scaledExtentNotifier: _scaledExtentNotifier, scaledExtentNotifier: _scaledExtentNotifier,
showScaledGrid: widget.showScaledGrid,
), ),
); );
Overlay.of(scrollableContext).insert(_overlayEntry); Overlay.of(scrollableContext).insert(_overlayEntry);
@ -133,7 +127,16 @@ class _GridScaleGestureDetectorState<T> extends State<GridScaleGestureDetector<T
}); });
} }
}, },
child: widget.child, child: GestureDetector(
// Horizontal/vertical drag gestures are interpreted as scaling
// if they are not handled by `onHorizontalDragStart`/`onVerticalDragStart`
// at the scaling `GestureDetector` level, or handled beforehand down the widget tree.
// Setting `onHorizontalDragStart`, `onVerticalDragStart`, and `onScaleStart`
// all at once is not allowed, so we use another `GestureDetector` for that.
onVerticalDragStart: (details) {},
onHorizontalDragStart: (details) {},
child: widget.child,
),
); );
} }
@ -157,18 +160,16 @@ class _GridScaleGestureDetectorState<T> extends State<GridScaleGestureDetector<T
class ScaleOverlay extends StatefulWidget { class ScaleOverlay extends StatefulWidget {
final Widget Function(double extent) builder; final Widget Function(double extent) builder;
final Offset center; final Offset center;
final double gridWidth; final double viewportWidth;
final double spacing;
final ValueNotifier<double> scaledExtentNotifier; final ValueNotifier<double> scaledExtentNotifier;
final bool showScaledGrid; final Widget Function(Offset center, double extent, Widget child) gridBuilder;
const ScaleOverlay({ const ScaleOverlay({
@required this.builder, @required this.builder,
@required this.center, @required this.center,
@required this.gridWidth, @required this.viewportWidth,
@required this.spacing,
@required this.scaledExtentNotifier, @required this.scaledExtentNotifier,
@required this.showScaledGrid, this.gridBuilder,
}); });
@override @override
@ -180,7 +181,7 @@ class _ScaleOverlayState extends State<ScaleOverlay> {
Offset get center => widget.center; Offset get center => widget.center;
double get gridWidth => widget.gridWidth; double get gridWidth => widget.viewportWidth;
@override @override
void initState() { void initState() {
@ -241,16 +242,7 @@ class _ScaleOverlayState extends State<ScaleOverlay> {
), ),
], ],
); );
if (widget.showScaledGrid) { child = widget.gridBuilder?.call(clampedCenter, extent, child) ?? child;
child = CustomPaint(
painter: GridPainter(
center: clampedCenter,
extent: extent,
spacing: widget.spacing,
),
child: child,
);
}
return child; return child;
}, },
), ),
@ -263,31 +255,36 @@ class _ScaleOverlayState extends State<ScaleOverlay> {
class GridPainter extends CustomPainter { class GridPainter extends CustomPainter {
final Offset center; final Offset center;
final double extent, spacing; final double extent, spacing;
final double strokeWidth;
final Color color;
const GridPainter({ const GridPainter({
@required this.center, @required this.center,
@required this.extent, @required this.extent,
@required this.spacing, this.spacing = 0.0,
this.strokeWidth = 1.0,
@required this.color,
}); });
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
final radius = extent * 3;
final paint = Paint() final paint = Paint()
..strokeWidth = DecoratedThumbnail.borderWidth ..strokeWidth = strokeWidth
..shader = ui.Gradient.radial( ..shader = ui.Gradient.radial(
center, center,
size.width * .7, radius,
[ [
DecoratedThumbnail.borderColor, color,
Colors.transparent, Colors.transparent,
], ],
[ [
min(.5, 2 * extent / size.width), extent / radius,
1, 1,
], ],
); );
void draw(Offset topLeft) { void draw(Offset topLeft) {
for (var i = -2; i <= 3; i++) { for (var i = -1; i <= 2; i++) {
final ref = (extent + spacing) * i; final ref = (extent + spacing) * i;
canvas.drawLine(Offset(0, topLeft.dy + ref), Offset(size.width, topLeft.dy + ref), paint); canvas.drawLine(Offset(0, topLeft.dy + ref), Offset(size.width, topLeft.dy + ref), paint);
canvas.drawLine(Offset(topLeft.dx + ref, 0), Offset(topLeft.dx + ref, size.height), paint); canvas.drawLine(Offset(topLeft.dx + ref, 0), Offset(topLeft.dx + ref, size.height), paint);

View file

@ -6,15 +6,16 @@ import 'package:flutter/widgets.dart';
class TileExtentManager { class TileExtentManager {
final String settingsRouteKey; final String settingsRouteKey;
final int columnCountMin, columnCountDefault; final int columnCountMin, columnCountDefault;
final double spacing, extentMin; final double spacing, extentMin, extentMax;
final ValueNotifier<double> extentNotifier; final ValueNotifier<double> extentNotifier;
const TileExtentManager({ const TileExtentManager({
@required this.settingsRouteKey, @required this.settingsRouteKey,
@required this.columnCountMin, @required this.extentNotifier,
this.columnCountMin = 2,
@required this.columnCountDefault, @required this.columnCountDefault,
@required this.extentMin, @required this.extentMin,
@required this.extentNotifier, this.extentMax = 300,
@required this.spacing, @required this.spacing,
}); });
@ -46,7 +47,7 @@ class TileExtentManager {
return newExtent; return newExtent;
} }
double _extentMax(Size viewportSize) => (viewportSize.shortestSide - spacing * (columnCountMin - 1)) / columnCountMin; double _extentMax(Size viewportSize) => min(extentMax, (viewportSize.shortestSide - spacing * (columnCountMin - 1)) / columnCountMin);
double _columnCountForExtent(Size viewportSize, double extent) => (viewportSize.width + spacing) / (extent + spacing); double _columnCountForExtent(Size viewportSize, double extent) => (viewportSize.width + spacing) / (extent + spacing);

View file

@ -37,6 +37,8 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
final ValueNotifier<double> _tileExtentNotifier = ValueNotifier(0); final ValueNotifier<double> _tileExtentNotifier = ValueNotifier(0);
final GlobalKey _scrollableKey = GlobalKey(); final GlobalKey _scrollableKey = GlobalKey();
static const columnCountDefault = 2;
static const extentMin = 60.0;
static const spacing = 8.0; static const spacing = 8.0;
FilterGridPage({ FilterGridPage({
@ -71,10 +73,9 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
final tileExtentManager = TileExtentManager( final tileExtentManager = TileExtentManager(
settingsRouteKey: settingsRouteKey ?? context.currentRouteName, settingsRouteKey: settingsRouteKey ?? context.currentRouteName,
columnCountMin: 2,
columnCountDefault: 2,
extentMin: 60,
extentNotifier: _tileExtentNotifier, extentNotifier: _tileExtentNotifier,
columnCountDefault: columnCountDefault,
extentMin: extentMin,
spacing: spacing, spacing: spacing,
)..applyTileExtent(viewportSize: viewportSize); )..applyTileExtent(viewportSize: viewportSize);
@ -98,7 +99,15 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
scrollableKey: _scrollableKey, scrollableKey: _scrollableKey,
appBarHeightNotifier: _appBarHeightNotifier, appBarHeightNotifier: _appBarHeightNotifier,
viewportSize: viewportSize, viewportSize: viewportSize,
showScaledGrid: true, gridBuilder: (center, extent, child) => CustomPaint(
painter: GridPainter(
center: center,
extent: extent,
spacing: tileExtentManager.spacing,
color: Colors.grey.shade700,
),
child: child,
),
scaledBuilder: (item, extent) { scaledBuilder: (item, extent) {
final filter = item.filter; final filter = item.filter;
return SizedBox( return SizedBox(