diff --git a/lib/widgets/common/aves_filter_chip.dart b/lib/widgets/common/aves_filter_chip.dart index 8d002b129..19adca22d 100644 --- a/lib/widgets/common/aves_filter_chip.dart +++ b/lib/widgets/common/aves_filter_chip.dart @@ -10,7 +10,7 @@ class AvesFilterChip extends StatefulWidget { final CollectionFilter filter; final bool removable; final bool showGenericIcon; - final Decoration decoration; + final Widget background; final Widget details; final HeroType heroType; final FilterCallback onPressed; @@ -28,7 +28,7 @@ class AvesFilterChip extends StatefulWidget { this.filter, this.removable = false, this.showGenericIcon = true, - this.decoration, + this.background, this.details, this.heroType = HeroType.onTap, @required this.onPressed, @@ -64,11 +64,12 @@ class _AvesFilterChipState extends State { @override Widget build(BuildContext context) { + final hasBackground = widget.background != null; final leading = filter.iconBuilder(context, AvesFilterChip.iconSize, showGenericIcon: widget.showGenericIcon); final trailing = widget.removable ? const Icon(AIcons.clear, size: AvesFilterChip.iconSize) : null; Widget content = Row( - mainAxisSize: widget.decoration != null ? MainAxisSize.max : MainAxisSize.min, + mainAxisSize: hasBackground ? MainAxisSize.max : MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ if (leading != null) ...[ @@ -105,7 +106,7 @@ class _AvesFilterChipState extends State { child: content, ); - if (widget.decoration != null) { + if (hasBackground) { content = Center( child: ColoredBox( color: Colors.black54, @@ -132,45 +133,54 @@ class _AvesFilterChipState extends State { maxWidth: AvesFilterChip.maxChipWidth, minHeight: AvesFilterChip.minChipHeight, ), - decoration: widget.decoration, - child: Tooltip( - message: filter.tooltip, - preferBelow: false, - child: Material( - color: widget.decoration != null ? Colors.transparent : Theme.of(context).scaffoldBackgroundColor, - shape: RoundedRectangleBorder( - borderRadius: borderRadius, - ), - child: InkWell( - onTap: widget.onPressed != null - ? () { - WidgetsBinding.instance.addPostFrameCallback((_) => widget.onPressed(filter)); - setState(() => _tapped = true); - } - : null, - borderRadius: borderRadius, - child: FutureBuilder( - future: _colorFuture, - builder: (context, AsyncSnapshot snapshot) { - final outlineColor = snapshot.hasData ? snapshot.data : Colors.transparent; - return DecoratedBox( - decoration: BoxDecoration( - border: Border.all( - color: outlineColor, - width: AvesFilterChip.outlineWidth, - ), - borderRadius: borderRadius, - ), - position: DecorationPosition.foreground, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: content, - ), - ); - }, + child: Stack( + fit: StackFit.passthrough, + children: [ + if (widget.background != null) + ClipRRect( + borderRadius: borderRadius, + child: widget.background, + ), + Tooltip( + message: filter.tooltip, + preferBelow: false, + child: Material( + color: hasBackground ? Colors.transparent : Theme.of(context).scaffoldBackgroundColor, + shape: RoundedRectangleBorder( + borderRadius: borderRadius, + ), + child: InkWell( + onTap: widget.onPressed != null + ? () { + WidgetsBinding.instance.addPostFrameCallback((_) => widget.onPressed(filter)); + setState(() => _tapped = true); + } + : null, + borderRadius: borderRadius, + child: FutureBuilder( + future: _colorFuture, + builder: (context, AsyncSnapshot snapshot) { + final outlineColor = snapshot.hasData ? snapshot.data : Colors.transparent; + return DecoratedBox( + decoration: BoxDecoration( + border: Border.all( + color: outlineColor, + width: AvesFilterChip.outlineWidth, + ), + borderRadius: borderRadius, + ), + position: DecorationPosition.foreground, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: content, + ), + ); + }, + ), + ), ), ), - ), + ], ), ); diff --git a/lib/widgets/filter_grid_page.dart b/lib/widgets/filter_grid_page.dart index 058d9b419..612ac39ef 100644 --- a/lib/widgets/filter_grid_page.dart +++ b/lib/widgets/filter_grid_page.dart @@ -1,4 +1,3 @@ -import 'dart:typed_data'; import 'dart:ui'; import 'package:aves/model/collection_lens.dart'; @@ -7,17 +6,16 @@ import 'package:aves/model/filters/album.dart'; import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/image_entry.dart'; import 'package:aves/model/settings.dart'; -import 'package:aves/services/image_file_service.dart'; import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/widgets/album/collection_page.dart'; +import 'package:aves/widgets/album/thumbnail/raster.dart'; +import 'package:aves/widgets/album/thumbnail/vector.dart'; import 'package:aves/widgets/app_drawer.dart'; import 'package:aves/widgets/common/aves_filter_chip.dart'; import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart'; import 'package:aves/widgets/common/icons.dart'; -import 'package:aves/widgets/common/image_providers/thumbnail_provider.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; class FilterNavigationPage extends StatelessWidget { @@ -158,7 +156,7 @@ class FilterGridPage extends StatelessWidget { } } -class DecoratedFilterChip extends StatefulWidget { +class DecoratedFilterChip extends StatelessWidget { final CollectionSource source; final CollectionFilter filter; final ImageEntry entry; @@ -171,92 +169,26 @@ class DecoratedFilterChip extends StatefulWidget { @required this.onPressed, }); - @override - _DecoratedFilterChipState createState() => _DecoratedFilterChipState(); -} - -class _DecoratedFilterChipState extends State { - CollectionSource get source => widget.source; - - CollectionFilter get filter => widget.filter; - - ImageEntry get entry => widget.entry; - - Future _svgByteLoader; - - @override - void initState() { - super.initState(); - _svgByteLoader = _initSvgByteLoader(); - } - - @override - void didUpdateWidget(DecoratedFilterChip oldWidget) { - super.didUpdateWidget(oldWidget); - if (oldWidget.entry != entry) { - _svgByteLoader = _initSvgByteLoader(); - } - } - - Future _initSvgByteLoader() async { - if (entry == null || !entry.isSvg) return null; - - final uri = entry.uri; - final bytes = await ImageFileService.getImage(uri, entry.mimeType); - if (bytes == null || bytes.isEmpty) return bytes; - - final svgRoot = await svg.fromSvgBytes(bytes, uri); - const extent = FilterGridPage.maxCrossAxisExtent; - final picture = svgRoot.toPicture(size: const Size(extent, extent)); - final uiImage = await picture.toImage(extent.ceil(), extent.ceil()); - final data = await uiImage.toByteData(format: ImageByteFormat.png); - return data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); - } - @override Widget build(BuildContext context) { - if (entry == null || !entry.isSvg) { - Decoration decoration; - if (entry != null) { - decoration = BoxDecoration( - image: DecorationImage( - image: ThumbnailProvider( + Widget backgroundImage; + if (entry != null) { + backgroundImage = entry.isSvg + ? ThumbnailVectorImage( entry: entry, extent: FilterGridPage.maxCrossAxisExtent, - ), - fit: BoxFit.cover, - ), - borderRadius: AvesFilterChip.borderRadius, - ); - } - return _buildChip(decoration); + ) + : ThumbnailRasterImage( + entry: entry, + extent: FilterGridPage.maxCrossAxisExtent, + ); } - - return FutureBuilder( - future: _svgByteLoader, - builder: (context, AsyncSnapshot snapshot) { - Decoration decoration; - if (!snapshot.hasError && snapshot.connectionState == ConnectionState.done) { - decoration = BoxDecoration( - image: DecorationImage( - image: MemoryImage(snapshot.data), - fit: BoxFit.cover, - ), - borderRadius: AvesFilterChip.borderRadius, - ); - } - return _buildChip(decoration); - }, - ); - } - - AvesFilterChip _buildChip(Decoration decoration) { return AvesFilterChip( filter: filter, showGenericIcon: false, - decoration: decoration, + background: backgroundImage, details: _buildDetails(filter), - onPressed: widget.onPressed, + onPressed: onPressed, ); }