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

View file

@ -87,6 +87,7 @@ class _LicensesState extends State<Licenses> {
Widget _buildHeader() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
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/source/collection_lens.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:provider/provider.dart';
@ -15,14 +14,14 @@ class SectionedListLayoutProvider extends StatelessWidget {
final Widget Function(ImageEntry entry) thumbnailBuilder;
final Widget child;
SectionedListLayoutProvider({
const SectionedListLayoutProvider({
@required this.collection,
@required this.scrollableWidth,
@required this.tileExtent,
@required this.columnCount,
@required this.thumbnailBuilder,
@required this.child,
}) : assert(scrollableWidth != 0),
columnCount = max((scrollableWidth / tileExtent).round(), ThumbnailCollection.columnCountMin);
}) : assert(scrollableWidth != 0);
@override
Widget build(BuildContext context) {

View file

@ -31,9 +31,9 @@ class ThumbnailCollection extends StatelessWidget {
final ValueNotifier<bool> _isScrollingNotifier = ValueNotifier(false);
final GlobalKey _scrollableKey = GlobalKey();
static const columnCountMin = 2;
static const columnCountDefault = 4;
static const extentMin = 46.0;
static const spacing = 0.0;
@override
Widget build(BuildContext context) {
@ -47,11 +47,10 @@ class ThumbnailCollection extends StatelessWidget {
final tileExtentManager = TileExtentManager(
settingsRouteKey: context.currentRouteName,
columnCountMin: columnCountMin,
extentNotifier: _tileExtentNotifier,
columnCountDefault: columnCountDefault,
extentMin: extentMin,
extentNotifier: _tileExtentNotifier,
spacing: 0,
spacing: spacing,
)..applyTileExtent(viewportSize: viewportSize);
final cacheExtent = tileExtentManager.getEffectiveExtentMax(viewportSize) * 2;
@ -77,7 +76,18 @@ class ThumbnailCollection extends StatelessWidget {
scrollableKey: _scrollableKey,
appBarHeightNotifier: _appBarHeightNotifier,
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(
entry: entry,
extent: extent,
@ -98,6 +108,7 @@ class ThumbnailCollection extends StatelessWidget {
collection: collection,
scrollableWidth: viewportSize.width,
tileExtent: tileExtent,
columnCount: tileExtentManager.getEffectiveColumnCountForExtent(viewportSize, tileExtent),
thumbnailBuilder: (entry) => GridThumbnail(
key: ValueKey(entry.contentId),
collection: collection,

View file

@ -2,7 +2,6 @@ import 'dart:math';
import 'dart:ui' as ui;
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/tile_extent_manager.dart';
import 'package:flutter/material.dart';
@ -20,7 +19,7 @@ class GridScaleGestureDetector<T> extends StatefulWidget {
final GlobalKey scrollableKey;
final ValueNotifier<double> appBarHeightNotifier;
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 Rect Function(BuildContext context, T item) getScaledItemTileRect;
final void Function(T item) onScaled;
@ -31,7 +30,7 @@ class GridScaleGestureDetector<T> extends StatefulWidget {
@required this.scrollableKey,
@required this.appBarHeightNotifier,
@required this.viewportSize,
@required this.showScaledGrid,
this.gridBuilder,
@required this.scaledBuilder,
@required this.getScaledItemTileRect,
@required this.onScaled,
@ -56,10 +55,6 @@ class _GridScaleGestureDetectorState<T> extends State<GridScaleGestureDetector<T
@override
Widget build(BuildContext context) {
return GestureDetector(
onHorizontalDragStart: (details) {
// if `onHorizontalDragStart` callback is not defined,
// horizontal drag gestures are interpreted as scaling
},
onScaleStart: (details) {
// the gesture detector wrongly detects a new scaling gesture
// 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: (extent) => widget.scaledBuilder(_metadata.item, extent),
center: thumbnailCenter,
gridWidth: gridWidth,
spacing: tileExtentManager.spacing,
viewportWidth: gridWidth,
gridBuilder: widget.gridBuilder,
scaledExtentNotifier: _scaledExtentNotifier,
showScaledGrid: widget.showScaledGrid,
),
);
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 {
final Widget Function(double extent) builder;
final Offset center;
final double gridWidth;
final double spacing;
final double viewportWidth;
final ValueNotifier<double> scaledExtentNotifier;
final bool showScaledGrid;
final Widget Function(Offset center, double extent, Widget child) gridBuilder;
const ScaleOverlay({
@required this.builder,
@required this.center,
@required this.gridWidth,
@required this.spacing,
@required this.viewportWidth,
@required this.scaledExtentNotifier,
@required this.showScaledGrid,
this.gridBuilder,
});
@override
@ -180,7 +181,7 @@ class _ScaleOverlayState extends State<ScaleOverlay> {
Offset get center => widget.center;
double get gridWidth => widget.gridWidth;
double get gridWidth => widget.viewportWidth;
@override
void initState() {
@ -241,16 +242,7 @@ class _ScaleOverlayState extends State<ScaleOverlay> {
),
],
);
if (widget.showScaledGrid) {
child = CustomPaint(
painter: GridPainter(
center: clampedCenter,
extent: extent,
spacing: widget.spacing,
),
child: child,
);
}
child = widget.gridBuilder?.call(clampedCenter, extent, child) ?? child;
return child;
},
),
@ -263,31 +255,36 @@ class _ScaleOverlayState extends State<ScaleOverlay> {
class GridPainter extends CustomPainter {
final Offset center;
final double extent, spacing;
final double strokeWidth;
final Color color;
const GridPainter({
@required this.center,
@required this.extent,
@required this.spacing,
this.spacing = 0.0,
this.strokeWidth = 1.0,
@required this.color,
});
@override
void paint(Canvas canvas, Size size) {
final radius = extent * 3;
final paint = Paint()
..strokeWidth = DecoratedThumbnail.borderWidth
..strokeWidth = strokeWidth
..shader = ui.Gradient.radial(
center,
size.width * .7,
radius,
[
DecoratedThumbnail.borderColor,
color,
Colors.transparent,
],
[
min(.5, 2 * extent / size.width),
extent / radius,
1,
],
);
void draw(Offset topLeft) {
for (var i = -2; i <= 3; i++) {
for (var i = -1; i <= 2; i++) {
final ref = (extent + spacing) * i;
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);

View file

@ -6,15 +6,16 @@ import 'package:flutter/widgets.dart';
class TileExtentManager {
final String settingsRouteKey;
final int columnCountMin, columnCountDefault;
final double spacing, extentMin;
final double spacing, extentMin, extentMax;
final ValueNotifier<double> extentNotifier;
const TileExtentManager({
@required this.settingsRouteKey,
@required this.columnCountMin,
@required this.extentNotifier,
this.columnCountMin = 2,
@required this.columnCountDefault,
@required this.extentMin,
@required this.extentNotifier,
this.extentMax = 300,
@required this.spacing,
});
@ -46,7 +47,7 @@ class TileExtentManager {
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);

View file

@ -37,6 +37,8 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
final ValueNotifier<double> _tileExtentNotifier = ValueNotifier(0);
final GlobalKey _scrollableKey = GlobalKey();
static const columnCountDefault = 2;
static const extentMin = 60.0;
static const spacing = 8.0;
FilterGridPage({
@ -71,10 +73,9 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
final tileExtentManager = TileExtentManager(
settingsRouteKey: settingsRouteKey ?? context.currentRouteName,
columnCountMin: 2,
columnCountDefault: 2,
extentMin: 60,
extentNotifier: _tileExtentNotifier,
columnCountDefault: columnCountDefault,
extentMin: extentMin,
spacing: spacing,
)..applyTileExtent(viewportSize: viewportSize);
@ -98,7 +99,15 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
scrollableKey: _scrollableKey,
appBarHeightNotifier: _appBarHeightNotifier,
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) {
final filter = item.filter;
return SizedBox(