Cache photos to the left and right

This commit is contained in:
Vishnu Mohandas 2020-06-10 23:47:54 +05:30
parent a659fefa6d
commit 59dcc38ba5
6 changed files with 135 additions and 26 deletions

View file

@ -0,0 +1,7 @@
import 'package:photos/models/photo.dart';
class PhotoOpenedEvent {
final Photo photo;
PhotoOpenedEvent(this.photo);
}

View file

@ -1,8 +1,11 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:like_button/like_button.dart'; import 'package:like_button/like_button.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/photo_opened_event.dart';
import 'package:photos/favorite_photos_repository.dart'; import 'package:photos/favorite_photos_repository.dart';
import 'package:photos/models/photo.dart'; import 'package:photos/models/photo.dart';
import 'package:photos/ui/extents_page_view.dart';
import 'package:photos/ui/zoomable_image.dart'; import 'package:photos/ui/zoomable_image.dart';
import 'package:photos/utils/share_util.dart'; import 'package:photos/utils/share_util.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
@ -52,29 +55,35 @@ class _DetailPageState extends State<DetailPage> {
Widget _buildPageView() { Widget _buildPageView() {
_pageController = PageController(initialPage: _selectedIndex); _pageController = PageController(initialPage: _selectedIndex);
return PageView.builder( return ExtentsPageView.extents(
itemBuilder: (context, index) { itemBuilder: (context, index) {
final photo = _photos[index]; final photo = _photos[index];
final image = ZoomableImage( final image = Hero(
tag: photo.hashCode,
child: ZoomableImage(
photo, photo,
shouldDisableScroll: (value) { shouldDisableScroll: (value) {
setState(() { setState(() {
_shouldDisableScroll = value; _shouldDisableScroll = value;
}); });
}, },
),
); );
if (index == _selectedIndex) {
Bus.instance.fire(PhotoOpenedEvent(photo));
}
return image; return image;
}, },
onPageChanged: (int index) { onPageChanged: (int index) {
setState(() {
_selectedIndex = index; _selectedIndex = index;
}); Bus.instance.fire(PhotoOpenedEvent(widget.photos[index]));
}, },
physics: _shouldDisableScroll physics: _shouldDisableScroll
? NeverScrollableScrollPhysics() ? NeverScrollableScrollPhysics()
: PageScrollPhysics(), : PageScrollPhysics(),
controller: _pageController, controller: _pageController,
itemCount: _photos.length, itemCount: _photos.length,
extents: 1,
); );
} }

View file

@ -1,8 +1,11 @@
import 'dart:async';
import 'dart:collection'; import 'dart:collection';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/photo_opened_event.dart';
import 'package:photos/models/photo.dart'; import 'package:photos/models/photo.dart';
import 'package:photos/photo_sync_manager.dart'; import 'package:photos/photo_sync_manager.dart';
import 'package:photos/ui/detail_page.dart'; import 'package:photos/ui/detail_page.dart';
@ -32,6 +35,24 @@ class _GalleryState extends State<Gallery> {
List<Photo> _photos; List<Photo> _photos;
RefreshController _refreshController = RefreshController _refreshController =
RefreshController(initialRefresh: false); RefreshController(initialRefresh: false);
StreamSubscription<PhotoOpenedEvent> _subscription;
Photo _openedPhoto;
@override
void initState() {
_subscription = Bus.instance.on<PhotoOpenedEvent>().listen((event) {
setState(() {
_openedPhoto = event.photo;
});
});
super.initState();
}
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -127,10 +148,9 @@ class _GalleryState extends State<Gallery> {
? Border.all(width: 4.0, color: Colors.blue) ? Border.all(width: 4.0, color: Colors.blue)
: null, : null,
), ),
child: Hero( child: photo == _openedPhoto
tag: photo.hashCode, ? Hero(tag: photo.hashCode, child: ThumbnailWidget(photo))
child: ThumbnailWidget(photo), : ThumbnailWidget(photo),
),
), ),
); );
} }

View file

@ -1,3 +1,4 @@
import 'package:extended_image/extended_image.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:photos/core/cache/image_cache.dart'; import 'package:photos/core/cache/image_cache.dart';
@ -21,7 +22,8 @@ class ZoomableImage extends StatefulWidget {
_ZoomableImageState createState() => _ZoomableImageState(); _ZoomableImageState createState() => _ZoomableImageState();
} }
class _ZoomableImageState extends State<ZoomableImage> { class _ZoomableImageState extends State<ZoomableImage>
with SingleTickerProviderStateMixin {
ImageProvider _imageProvider; ImageProvider _imageProvider;
bool _loadedSmallThumbnail = false; bool _loadedSmallThumbnail = false;
bool _loadingLargeThumbnail = false; bool _loadingLargeThumbnail = false;
@ -29,6 +31,10 @@ class _ZoomableImageState extends State<ZoomableImage> {
bool _loadingFinalImage = false; bool _loadingFinalImage = false;
bool _loadedFinalImage = false; bool _loadedFinalImage = false;
ValueChanged<PhotoViewScaleState> _scaleStateChangedCallback; ValueChanged<PhotoViewScaleState> _scaleStateChangedCallback;
// AnimationController _animationController;
// Animation _animation;
// VoidCallback _animationListener;
final doubleTapScales = [1.0, 2.0];
@override @override
void initState() { void initState() {
@ -37,6 +43,10 @@ class _ZoomableImageState extends State<ZoomableImage> {
widget.shouldDisableScroll(value != PhotoViewScaleState.initial); widget.shouldDisableScroll(value != PhotoViewScaleState.initial);
} }
}; };
// _animationController = AnimationController(
// vsync: this,
// duration: const Duration(milliseconds: 100),
// );
super.initState(); super.initState();
} }
@ -49,12 +59,46 @@ class _ZoomableImageState extends State<ZoomableImage> {
} }
if (_imageProvider != null) { if (_imageProvider != null) {
// return ExtendedImage(
// image: _imageProvider,
// gaplessPlayback: true,
// mode: ExtendedImageMode.gesture,
// enableSlideOutPage: true,
// initGestureConfigHandler: (state) {
// return GestureConfig(
// inPageView: true,
// initialScale: 1.0,
// minScale: 1.0,
// );
// },
// onDoubleTap: (ExtendedImageGestureState state) {
// var pointerDownPosition = state.pointerDownPosition;
// double begin = state.gestureDetails.totalScale;
// double end;
// _animation?.removeListener(_animationListener);
// _animationController.stop();
// _animationController.reset();
// if (begin == doubleTapScales[0]) {
// end = doubleTapScales[1];
// } else {
// end = doubleTapScales[0];
// }
// _animationListener = () {
// state.handleDoubleTap(
// scale: _animation.value,
// doubleTapPosition: pointerDownPosition);
// };
// _animation =
// _animationController.drive(Tween<double>(begin: begin, end: end));
// _animation.addListener(_animationListener);
// _animationController.forward();
// },
// );
return PhotoView( return PhotoView(
imageProvider: _imageProvider, imageProvider: _imageProvider,
scaleStateChangedCallback: _scaleStateChangedCallback, scaleStateChangedCallback: _scaleStateChangedCallback,
minScale: PhotoViewComputedScale.contained, minScale: PhotoViewComputedScale.contained,
gaplessPlayback: true, gaplessPlayback: true,
heroAttributes: PhotoViewHeroAttributes(tag: widget.photo.hashCode),
); );
} else { } else {
return loadWidget; return loadWidget;

View file

@ -36,6 +36,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.3" version: "1.1.3"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
collection: collection:
dependency: transitive dependency: transitive
description: description:
@ -120,6 +127,27 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
extended_image:
dependency: "direct main"
description:
name: extended_image
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.0"
extended_image_library:
dependency: transitive
description:
name: extended_image_library
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.3"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -191,6 +219,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.1" version: "0.12.1"
http_client_helper:
dependency: transitive
description:
name: http_client_helper
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.1"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@ -267,7 +302,7 @@ packages:
name: path name: path
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.4" version: "1.7.0"
path_provider: path_provider:
dependency: "direct main" dependency: "direct main"
description: description:
@ -345,13 +380,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.5.8" version: "1.5.8"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
sensors: sensors:
dependency: transitive dependency: transitive
description: description:
@ -475,7 +503,7 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.15" version: "0.2.16"
toast: toast:
dependency: "direct main" dependency: "direct main"
description: description:

View file

@ -50,6 +50,7 @@ dependencies:
flutter_typeahead: ^1.8.1 flutter_typeahead: ^1.8.1
pull_to_refresh: ^1.5.7 pull_to_refresh: ^1.5.7
fluttertoast: ^4.0.1 fluttertoast: ^4.0.1
extended_image: ^0.9.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: