various minor fixes
This commit is contained in:
parent
154ceecae0
commit
3ef5cde4da
7 changed files with 73 additions and 52 deletions
|
@ -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',
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in a new issue