fixed scintillating thumbnail borders & selection overlay layout
This commit is contained in:
parent
c8c2537996
commit
14385eeadd
9 changed files with 58 additions and 40 deletions
|
@ -25,7 +25,7 @@ class EntryListDetails extends StatelessWidget {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EntryListDetailsTheme.contentPadding,
|
padding: EntryListDetailsTheme.contentPadding,
|
||||||
foregroundDecoration: BoxDecoration(
|
foregroundDecoration: BoxDecoration(
|
||||||
border: Border(top: AvesBorder.side),
|
border: Border(top: AvesBorder.straightSide),
|
||||||
),
|
),
|
||||||
margin: EntryListDetailsTheme.contentMargin,
|
margin: EntryListDetailsTheme.contentMargin,
|
||||||
child: IconTheme.merge(
|
child: IconTheme.merge(
|
||||||
|
|
|
@ -6,12 +6,22 @@ class AvesBorder {
|
||||||
static const borderColor = Colors.white30;
|
static const borderColor = Colors.white30;
|
||||||
|
|
||||||
// directly uses `devicePixelRatio` as it never changes, to avoid visiting ancestors via `MediaQuery`
|
// directly uses `devicePixelRatio` as it never changes, to avoid visiting ancestors via `MediaQuery`
|
||||||
static double get borderWidth => window.devicePixelRatio > 2 ? 0.5 : 1.0;
|
|
||||||
|
|
||||||
static BorderSide get side => BorderSide(
|
// 1 device pixel for straight lines is fine
|
||||||
|
static double get straightBorderWidth => 1 / window.devicePixelRatio;
|
||||||
|
|
||||||
|
// 1 device pixel for curves is too thin
|
||||||
|
static double get curvedBorderWidth => window.devicePixelRatio > 2 ? 0.5 : 1.0;
|
||||||
|
|
||||||
|
static BorderSide get straightSide => BorderSide(
|
||||||
color: borderColor,
|
color: borderColor,
|
||||||
width: borderWidth,
|
width: straightBorderWidth,
|
||||||
);
|
);
|
||||||
|
|
||||||
static Border get border => Border.fromBorderSide(side);
|
static BorderSide get curvedSide => BorderSide(
|
||||||
|
color: borderColor,
|
||||||
|
width: curvedBorderWidth,
|
||||||
|
);
|
||||||
|
|
||||||
|
static Border get border => Border.fromBorderSide(curvedSide);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,9 @@ class GridItemSelectionOverlay<T> extends StatelessWidget {
|
||||||
? OverlayIcon(
|
? OverlayIcon(
|
||||||
key: ValueKey(isSelected),
|
key: ValueKey(isSelected),
|
||||||
icon: isSelected ? AIcons.selected : AIcons.unselected,
|
icon: isSelected ? AIcons.selected : AIcons.unselected,
|
||||||
|
margin: EdgeInsets.zero,
|
||||||
)
|
)
|
||||||
: const SizedBox.shrink();
|
: const SizedBox();
|
||||||
child = AnimatedSwitcher(
|
child = AnimatedSwitcher(
|
||||||
duration: duration,
|
duration: duration,
|
||||||
switchInCurve: Curves.easeOutBack,
|
switchInCurve: Curves.easeOutBack,
|
||||||
|
|
|
@ -50,8 +50,8 @@ class AnimatedImageIcon extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GeotiffIcon extends StatelessWidget {
|
class GeoTiffIcon extends StatelessWidget {
|
||||||
const GeotiffIcon({Key? key}) : super(key: key);
|
const GeoTiffIcon({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -181,12 +181,15 @@ class OverlayIcon extends StatelessWidget {
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
final String? text;
|
final String? text;
|
||||||
final double iconScale;
|
final double iconScale;
|
||||||
|
final EdgeInsets margin;
|
||||||
|
|
||||||
const OverlayIcon({
|
const OverlayIcon({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
this.iconScale = 1,
|
this.iconScale = 1,
|
||||||
this.text,
|
this.text,
|
||||||
|
// default margin for multiple icons in a `Column`
|
||||||
|
this.margin = const EdgeInsets.only(left: 1, right: 1, bottom: 1),
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -211,7 +214,7 @@ class OverlayIcon extends StatelessWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(left: 1, right: 1, bottom: 1),
|
margin: margin,
|
||||||
padding: text != null ? EdgeInsets.only(right: size / 4) : null,
|
padding: text != null ? EdgeInsets.only(right: size / 4) : null,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xBB000000),
|
color: const Color(0xBB000000),
|
||||||
|
|
|
@ -13,7 +13,7 @@ class DecoratedThumbnail extends StatelessWidget {
|
||||||
final Object? Function()? heroTagger;
|
final Object? Function()? heroTagger;
|
||||||
|
|
||||||
static final Color borderColor = Colors.grey.shade700;
|
static final Color borderColor = Colors.grey.shade700;
|
||||||
static final double borderWidth = AvesBorder.borderWidth;
|
static final double borderWidth = AvesBorder.straightBorderWidth;
|
||||||
|
|
||||||
const DecoratedThumbnail({
|
const DecoratedThumbnail({
|
||||||
Key? key,
|
Key? key,
|
||||||
|
@ -27,12 +27,10 @@ class DecoratedThumbnail extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final imageExtent = tileExtent - borderWidth * 2;
|
|
||||||
|
|
||||||
final isSvg = entry.isSvg;
|
final isSvg = entry.isSvg;
|
||||||
Widget child = ThumbnailImage(
|
Widget child = ThumbnailImage(
|
||||||
entry: entry,
|
entry: entry,
|
||||||
extent: imageExtent,
|
extent: tileExtent,
|
||||||
cancellableNotifier: cancellableNotifier,
|
cancellableNotifier: cancellableNotifier,
|
||||||
heroTag: heroTagger?.call(),
|
heroTag: heroTagger?.call(),
|
||||||
);
|
);
|
||||||
|
@ -42,13 +40,19 @@ class DecoratedThumbnail extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
child,
|
child,
|
||||||
if (!isSvg) ThumbnailEntryOverlay(entry: entry),
|
if (!isSvg) ThumbnailEntryOverlay(entry: entry),
|
||||||
if (selectable) GridItemSelectionOverlay(item: entry),
|
if (selectable)
|
||||||
|
GridItemSelectionOverlay<AvesEntry>(
|
||||||
|
item: entry,
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
),
|
||||||
if (highlightable) ThumbnailHighlightOverlay(entry: entry),
|
if (highlightable) ThumbnailHighlightOverlay(entry: entry),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
// `decoration` with sub logical pixel width yields scintillating borders
|
||||||
|
// so we use `foregroundDecoration` instead
|
||||||
|
foregroundDecoration: BoxDecoration(
|
||||||
border: Border.fromBorderSide(BorderSide(
|
border: Border.fromBorderSide(BorderSide(
|
||||||
color: borderColor,
|
color: borderColor,
|
||||||
width: borderWidth,
|
width: borderWidth,
|
||||||
|
|
|
@ -28,7 +28,7 @@ class ThumbnailEntryOverlay extends StatelessWidget {
|
||||||
const AnimatedImageIcon()
|
const AnimatedImageIcon()
|
||||||
else ...[
|
else ...[
|
||||||
if (entry.isRaw && context.select<GridThemeData, bool>((t) => t.showRaw)) const RawIcon(),
|
if (entry.isRaw && context.select<GridThemeData, bool>((t) => t.showRaw)) const RawIcon(),
|
||||||
if (entry.isGeotiff) const GeotiffIcon(),
|
if (entry.isGeotiff) const GeoTiffIcon(),
|
||||||
if (entry.is360) const SphericalImageIcon(),
|
if (entry.is360) const SphericalImageIcon(),
|
||||||
],
|
],
|
||||||
if (entry.isMultiPage) ...[
|
if (entry.isMultiPage) ...[
|
||||||
|
@ -36,7 +36,7 @@ class ThumbnailEntryOverlay extends StatelessWidget {
|
||||||
if (!entry.isMotionPhoto) MultiPageIcon(entry: entry),
|
if (!entry.isMotionPhoto) MultiPageIcon(entry: entry),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
if (children.isEmpty) return const SizedBox.shrink();
|
if (children.isEmpty) return const SizedBox();
|
||||||
if (children.length == 1) return children.first;
|
if (children.length == 1) return children.first;
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
|
@ -37,7 +37,7 @@ class FilterListDetails<T extends CollectionFilter> extends StatelessWidget {
|
||||||
return Container(
|
return Container(
|
||||||
padding: FilterListDetailsTheme.contentPadding,
|
padding: FilterListDetailsTheme.contentPadding,
|
||||||
foregroundDecoration: BoxDecoration(
|
foregroundDecoration: BoxDecoration(
|
||||||
border: Border(top: AvesBorder.side),
|
border: Border(top: AvesBorder.straightSide),
|
||||||
),
|
),
|
||||||
margin: FilterListDetailsTheme.contentMargin,
|
margin: FilterListDetailsTheme.contentMargin,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
|
@ -38,7 +38,7 @@ class OverlayButton extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
// icon (24) + icon padding (8) + button padding (16) + border (1 or 2)
|
// icon (24) + icon padding (8) + button padding (16) + border (1 or 2)
|
||||||
static double getSize(BuildContext context) => 48.0 + AvesBorder.borderWidth * 2;
|
static double getSize(BuildContext context) => 48.0 + AvesBorder.curvedBorderWidth * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
class OverlayTextButton extends StatelessWidget {
|
class OverlayTextButton extends StatelessWidget {
|
||||||
|
@ -71,7 +71,7 @@ class OverlayTextButton extends StatelessWidget {
|
||||||
foregroundColor: MaterialStateProperty.all<Color>(Colors.white),
|
foregroundColor: MaterialStateProperty.all<Color>(Colors.white),
|
||||||
overlayColor: MaterialStateProperty.all<Color>(Colors.white.withOpacity(0.12)),
|
overlayColor: MaterialStateProperty.all<Color>(Colors.white.withOpacity(0.12)),
|
||||||
minimumSize: _minSize,
|
minimumSize: _minSize,
|
||||||
side: MaterialStateProperty.all<BorderSide>(AvesBorder.side),
|
side: MaterialStateProperty.all<BorderSide>(AvesBorder.curvedSide),
|
||||||
shape: MaterialStateProperty.all<OutlinedBorder>(const RoundedRectangleBorder(
|
shape: MaterialStateProperty.all<OutlinedBorder>(const RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(_borderRadius)),
|
borderRadius: BorderRadius.all(Radius.circular(_borderRadius)),
|
||||||
)),
|
)),
|
||||||
|
|
40
pubspec.lock
40
pubspec.lock
|
@ -119,14 +119,14 @@ packages:
|
||||||
name: connectivity_plus
|
name: connectivity_plus
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.2.0"
|
||||||
connectivity_plus_linux:
|
connectivity_plus_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: connectivity_plus_linux
|
name: connectivity_plus_linux
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.2.0"
|
||||||
connectivity_plus_macos:
|
connectivity_plus_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -140,14 +140,14 @@ packages:
|
||||||
name: connectivity_plus_platform_interface
|
name: connectivity_plus_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.2.0"
|
||||||
connectivity_plus_web:
|
connectivity_plus_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: connectivity_plus_web
|
name: connectivity_plus_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0+1"
|
version: "1.2.0"
|
||||||
connectivity_plus_windows:
|
connectivity_plus_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -210,21 +210,21 @@ packages:
|
||||||
name: device_info_plus
|
name: device_info_plus
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.0"
|
version: "3.2.1"
|
||||||
device_info_plus_linux:
|
device_info_plus_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: device_info_plus_linux
|
name: device_info_plus_linux
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.1"
|
||||||
device_info_plus_macos:
|
device_info_plus_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: device_info_plus_macos
|
name: device_info_plus_macos
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.1"
|
||||||
device_info_plus_platform_interface:
|
device_info_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -245,7 +245,7 @@ packages:
|
||||||
name: device_info_plus_windows
|
name: device_info_plus_windows
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.1"
|
||||||
equatable:
|
equatable:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -447,7 +447,7 @@ packages:
|
||||||
name: github
|
name: github
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.3.0"
|
version: "8.5.0"
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -475,7 +475,7 @@ packages:
|
||||||
name: google_maps_flutter_platform_interface
|
name: google_maps_flutter_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.3"
|
version: "2.1.4"
|
||||||
highlight:
|
highlight:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -734,7 +734,7 @@ packages:
|
||||||
name: path_provider_platform_interface
|
name: path_provider_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.2"
|
||||||
path_provider_windows:
|
path_provider_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -797,7 +797,7 @@ packages:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.1.0"
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -839,7 +839,7 @@ packages:
|
||||||
name: provider
|
name: provider
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.1"
|
version: "6.0.2"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -867,28 +867,28 @@ packages:
|
||||||
name: screen_brightness
|
name: screen_brightness
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.2+2"
|
version: "0.1.3"
|
||||||
screen_brightness_android:
|
screen_brightness_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: screen_brightness_android
|
name: screen_brightness_android
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.1"
|
version: "0.0.3"
|
||||||
screen_brightness_ios:
|
screen_brightness_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: screen_brightness_ios
|
name: screen_brightness_ios
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.2"
|
version: "0.0.4"
|
||||||
screen_brightness_platform_interface:
|
screen_brightness_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: screen_brightness_platform_interface
|
name: screen_brightness_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.2"
|
version: "0.0.3"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -1012,7 +1012,7 @@ packages:
|
||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.2.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1161,7 +1161,7 @@ packages:
|
||||||
name: url_launcher_platform_interface
|
name: url_launcher_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.4"
|
version: "2.0.5"
|
||||||
url_launcher_web:
|
url_launcher_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1231,7 +1231,7 @@ packages:
|
||||||
name: win32
|
name: win32
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.3"
|
||||||
wkt_parser:
|
wkt_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
Loading…
Reference in a new issue