multipage: thumbnail request cancellation
This commit is contained in:
parent
ff517925f6
commit
8fa3f18aef
7 changed files with 35 additions and 16 deletions
|
@ -172,6 +172,15 @@ class AvesEntry {
|
||||||
addressChangeNotifier.dispose();
|
addressChangeNotifier.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if (other.runtimeType != runtimeType) return false;
|
||||||
|
return other is AvesEntry && other.uri == uri && other.pageId == pageId && other._dateModifiedSecs == _dateModifiedSecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => hashValues(uri, pageId, _dateModifiedSecs);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => '$runtimeType#${shortHash(this)}{uri=$uri, path=$path, pageId=$pageId}';
|
String toString() => '$runtimeType#${shortHash(this)}{uri=$uri, path=$path, pageId=$pageId}';
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
class MultiPageInfo {
|
class MultiPageInfo {
|
||||||
|
final String uri;
|
||||||
final List<SinglePageInfo> pages;
|
final List<SinglePageInfo> pages;
|
||||||
|
|
||||||
int get pageCount => pages.length;
|
int get pageCount => pages.length;
|
||||||
|
|
||||||
MultiPageInfo({
|
MultiPageInfo({
|
||||||
|
@required this.uri,
|
||||||
this.pages,
|
this.pages,
|
||||||
}) {
|
}) {
|
||||||
if (pages.isNotEmpty) {
|
if (pages.isNotEmpty) {
|
||||||
|
@ -18,8 +20,11 @@ class MultiPageInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
factory MultiPageInfo.fromPageMaps(List<Map> pageMaps) {
|
factory MultiPageInfo.fromPageMaps(String uri, List<Map> pageMaps) {
|
||||||
return MultiPageInfo(pages: pageMaps.map((page) => SinglePageInfo.fromMap(page)).toList());
|
return MultiPageInfo(
|
||||||
|
uri: uri,
|
||||||
|
pages: pageMaps.map((page) => SinglePageInfo.fromMap(page)).toList(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
SinglePageInfo get defaultPage => pages.firstWhere((page) => page.isDefault, orElse: () => null);
|
SinglePageInfo get defaultPage => pages.firstWhere((page) => page.isDefault, orElse: () => null);
|
||||||
|
@ -29,7 +34,7 @@ class MultiPageInfo {
|
||||||
SinglePageInfo getById(int pageId) => pages.firstWhere((page) => page.pageId == pageId, orElse: () => null);
|
SinglePageInfo getById(int pageId) => pages.firstWhere((page) => page.pageId == pageId, orElse: () => null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => '$runtimeType#${shortHash(this)}{pages=$pages}';
|
String toString() => '$runtimeType#${shortHash(this)}{uri=$uri, pages=$pages}';
|
||||||
}
|
}
|
||||||
|
|
||||||
class SinglePageInfo implements Comparable<SinglePageInfo> {
|
class SinglePageInfo implements Comparable<SinglePageInfo> {
|
||||||
|
|
|
@ -89,7 +89,7 @@ class MetadataService {
|
||||||
'uri': entry.uri,
|
'uri': entry.uri,
|
||||||
});
|
});
|
||||||
final pageMaps = (result as List).cast<Map>();
|
final pageMaps = (result as List).cast<Map>();
|
||||||
return MultiPageInfo.fromPageMaps(pageMaps);
|
return MultiPageInfo.fromPageMaps(entry.uri, pageMaps);
|
||||||
} on PlatformException catch (e) {
|
} on PlatformException catch (e) {
|
||||||
debugPrint('getMultiPageInfo failed with code=${e.code}, exception=${e.message}, details=${e.details}');
|
debugPrint('getMultiPageInfo failed with code=${e.code}, exception=${e.message}, details=${e.details}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,10 @@ class InteractiveThumbnail extends StatelessWidget {
|
||||||
entry: entry,
|
entry: entry,
|
||||||
extent: tileExtent,
|
extent: tileExtent,
|
||||||
collection: collection,
|
collection: collection,
|
||||||
isScrollingNotifier: isScrollingNotifier,
|
// when the user is scrolling faster than we can retrieve the thumbnails,
|
||||||
|
// the retrieval task queue can pile up for thumbnails that got disposed
|
||||||
|
// in this case we pause the image retrieval task to get it out of the queue
|
||||||
|
cancellableNotifier: isScrollingNotifier,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,7 +9,7 @@ class DecoratedThumbnail extends StatelessWidget {
|
||||||
final AvesEntry entry;
|
final AvesEntry entry;
|
||||||
final double extent;
|
final double extent;
|
||||||
final CollectionLens collection;
|
final CollectionLens collection;
|
||||||
final ValueNotifier<bool> isScrollingNotifier;
|
final ValueNotifier<bool> cancellableNotifier;
|
||||||
final bool selectable, highlightable;
|
final bool selectable, highlightable;
|
||||||
|
|
||||||
static final Color borderColor = Colors.grey.shade700;
|
static final Color borderColor = Colors.grey.shade700;
|
||||||
|
@ -20,7 +20,7 @@ class DecoratedThumbnail extends StatelessWidget {
|
||||||
@required this.entry,
|
@required this.entry,
|
||||||
@required this.extent,
|
@required this.extent,
|
||||||
this.collection,
|
this.collection,
|
||||||
this.isScrollingNotifier,
|
this.cancellableNotifier,
|
||||||
this.selectable = true,
|
this.selectable = true,
|
||||||
this.highlightable = true,
|
this.highlightable = true,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
@ -40,7 +40,7 @@ class DecoratedThumbnail extends StatelessWidget {
|
||||||
: RasterImageThumbnail(
|
: RasterImageThumbnail(
|
||||||
entry: entry,
|
entry: entry,
|
||||||
extent: extent,
|
extent: extent,
|
||||||
isScrollingNotifier: isScrollingNotifier,
|
cancellableNotifier: cancellableNotifier,
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,14 @@ import 'package:flutter/material.dart';
|
||||||
class RasterImageThumbnail extends StatefulWidget {
|
class RasterImageThumbnail extends StatefulWidget {
|
||||||
final AvesEntry entry;
|
final AvesEntry entry;
|
||||||
final double extent;
|
final double extent;
|
||||||
final ValueNotifier<bool> isScrollingNotifier;
|
final ValueNotifier<bool> cancellableNotifier;
|
||||||
final Object heroTag;
|
final Object heroTag;
|
||||||
|
|
||||||
const RasterImageThumbnail({
|
const RasterImageThumbnail({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.entry,
|
@required this.entry,
|
||||||
@required this.extent,
|
@required this.extent,
|
||||||
this.isScrollingNotifier,
|
this.cancellableNotifier,
|
||||||
this.heroTag,
|
this.heroTag,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@ -70,11 +70,7 @@ class _RasterImageThumbnailState extends State<RasterImageThumbnail> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _pauseProvider() {
|
void _pauseProvider() {
|
||||||
final isScrolling = widget.isScrollingNotifier?.value ?? false;
|
if (widget.cancellableNotifier?.value ?? false) {
|
||||||
// when the user is scrolling faster than we can retrieve the thumbnails,
|
|
||||||
// the retrieval task queue can pile up for thumbnails that got disposed
|
|
||||||
// in this case we pause the image retrieval task to get it out of the queue
|
|
||||||
if (isScrolling) {
|
|
||||||
_fastThumbnailProvider?.pause();
|
_fastThumbnailProvider?.pause();
|
||||||
_sizedThumbnailProvider?.pause();
|
_sizedThumbnailProvider?.pause();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ class MultiPageOverlay extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MultiPageOverlayState extends State<MultiPageOverlay> {
|
class _MultiPageOverlayState extends State<MultiPageOverlay> {
|
||||||
|
final _cancellableNotifier = ValueNotifier(true);
|
||||||
ScrollController _scrollController;
|
ScrollController _scrollController;
|
||||||
bool _syncScroll = true;
|
bool _syncScroll = true;
|
||||||
|
|
||||||
|
@ -90,7 +91,8 @@ class _MultiPageOverlayState extends State<MultiPageOverlay> {
|
||||||
future: controller.info,
|
future: controller.info,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final multiPageInfo = snapshot.data;
|
final multiPageInfo = snapshot.data;
|
||||||
if ((multiPageInfo?.pageCount ?? 0) <= 1) return SizedBox.shrink();
|
if ((multiPageInfo?.pageCount ?? 0) <= 1) return SizedBox();
|
||||||
|
if (multiPageInfo.uri != mainEntry.uri) return SizedBox();
|
||||||
return Container(
|
return Container(
|
||||||
height: extent + separatorWidth * 2,
|
height: extent + separatorWidth * 2,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
|
@ -125,6 +127,10 @@ class _MultiPageOverlayState extends State<MultiPageOverlay> {
|
||||||
child: DecoratedThumbnail(
|
child: DecoratedThumbnail(
|
||||||
entry: pageEntry,
|
entry: pageEntry,
|
||||||
extent: extent,
|
extent: extent,
|
||||||
|
// the retrieval task queue can pile up for thumbnails of heavy pages
|
||||||
|
// (e.g. thumbnails of 15MP HEIF images inside 100MB+ HEIC containers)
|
||||||
|
// so we cancel these requests when possible
|
||||||
|
cancellableNotifier: _cancellableNotifier,
|
||||||
selectable: false,
|
selectable: false,
|
||||||
highlightable: false,
|
highlightable: false,
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue