Skip to content

Commit

Permalink
Merge pull request bluefireteam#124 from Carlit0/master
Browse files Browse the repository at this point in the history
UNLOCK image if image is zoomedOut
  • Loading branch information
renancaraujo authored Apr 18, 2019
2 parents f44c27f + 04a4997 commit 99ec0c5
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 26 deletions.
7 changes: 4 additions & 3 deletions example/lib/screens/examples/controller_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class _ControllerExampleState extends State<ControllerExample> {
controller = PhotoViewController();
controller
..scale = defScale
..scaleState = PhotoViewScaleState.zooming
..scaleState = PhotoViewScaleState.initial
..outputStateStream.listen(onControllerState);
super.initState();
}
Expand Down Expand Up @@ -112,7 +112,6 @@ class _ControllerExampleState extends State<ControllerExample> {
max: max,
onChanged: (double newRotation) {
controller.rotation = newRotation;
controller.scaleState = PhotoViewScaleState.zooming;
})),
Text(
"Scale ${value.scale}",
Expand All @@ -127,7 +126,9 @@ class _ControllerExampleState extends State<ControllerExample> {
max: maxScale,
onChanged: (double newScale) {
controller.scale = newScale;
controller.scaleState = PhotoViewScaleState.zooming;
controller.scaleState = newScale > defScale
? PhotoViewScaleState.zoomedIn
: PhotoViewScaleState.zoomedOut;
})),
],
);
Expand Down
10 changes: 5 additions & 5 deletions lib/photo_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ class _PhotoViewState extends State<PhotoView>
_controlledController = false;
controller = widget.controller;
}
controller.outputStateStream.listen(scaleStateListener);
controller.outputScaleStateStream.listen(scaleStateListener);
}

@override
Expand Down Expand Up @@ -341,9 +341,8 @@ class _PhotoViewState extends State<PhotoView>
}
}

void scaleStateListener(PhotoViewControllerValue value) {
if (widget.scaleStateChangedCallback != null &&
controller.scaleState != controller.prevValue.scaleState) {
void scaleStateListener(PhotoViewScaleState scaleState) {
if (widget.scaleStateChangedCallback != null) {
widget.scaleStateChangedCallback(controller.scaleState);
}
}
Expand Down Expand Up @@ -449,7 +448,8 @@ PhotoViewScaleState defaultScaleStateCycle(PhotoViewScaleState actual) {
return PhotoViewScaleState.originalSize;
case PhotoViewScaleState.originalSize:
return PhotoViewScaleState.initial;
case PhotoViewScaleState.zooming:
case PhotoViewScaleState.zoomedIn:
case PhotoViewScaleState.zoomedOut:
return PhotoViewScaleState.initial;
default:
return PhotoViewScaleState.initial;
Expand Down
5 changes: 4 additions & 1 deletion lib/photo_view_gallery.dart
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,10 @@ class _PhotoViewGalleryState extends State<PhotoViewGallery> {

void scaleStateChangedCallback(PhotoViewScaleState scaleState) {
setState(() {
_locked = scaleState != PhotoViewScaleState.initial;
_locked = (scaleState == PhotoViewScaleState.initial ||
scaleState == PhotoViewScaleState.zoomedOut)
? false
: true;
});
if (widget.scaleStateChangedCallback != null) {
widget.scaleStateChangedCallback(scaleState);
Expand Down
24 changes: 21 additions & 3 deletions lib/src/photo_view_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ typedef ScaleStateListener = void Function(double prevScale, double nextScale);
///
/// The default implementation used by [PhotoView] is [PhotoViewController].
abstract class PhotoViewControllerBase<T extends PhotoViewControllerValue> {
/// The output for state updates. Usually a broadcast [Stream]
/// The output for state/value updates. Usually a broadcast [Stream]
Stream<T> get outputStateStream;

/// The output for scaleState changes [Stream]
Stream<PhotoViewScaleState> get outputScaleStateStream;

/// The state value before the last change or the initial state if trhe state has not been changed.
T prevValue;

Expand All @@ -38,7 +41,7 @@ abstract class PhotoViewControllerBase<T extends PhotoViewControllerValue> {

/// The scale factor to transform the child (image or a customChild).
///
/// **Important**: Avoid setting this field without setting [scaleState] to [PhotoViewScaleState.zooming].
/// **Important**: Avoid setting this field without setting [scaleState] to [PhotoViewScaleState.zoomedIn] or [PhotoViewScaleState.zoomedOut]. <- this has to be chnaged in the future
double scale;

/// The rotation factor to transform the child (image or a customChild).
Expand All @@ -49,7 +52,8 @@ abstract class PhotoViewControllerBase<T extends PhotoViewControllerValue> {

/// A way to represent the step of the "doubletap gesture cycle" in which PhotoView is.
///
/// **Important**: This fields is rarely externally set to a value different than [PhotoViewScaleState.zooming] after setting a [scale].
/// **Important**: This fields is rarely externally set to a value different than [PhotoViewScaleState.zoomedIn] or [PhotoViewScaleState.zoomedOut] after setting a [scale].
/// future TODO: setting the controller.scale should also set the scaleState to [PhotoViewScaleState.zoomedIn] or [PhotoViewScaleState.zoomedOut]
PhotoViewScaleState scaleState;

/// Update multiple fields of the state with only one update streamed.
Expand Down Expand Up @@ -122,22 +126,30 @@ class PhotoViewController
_notifier.addListener(_changeListener);
_outputCtrl = StreamController<PhotoViewControllerValue>.broadcast();
_outputCtrl.sink.add(initial);
_outputScaleStateCtrl = StreamController<PhotoViewScaleState>();
_outputScaleStateCtrl.sink.add(PhotoViewScaleState.initial);
}

ValueNotifier<PhotoViewControllerValue> _notifier;
PhotoViewControllerValue initial;

StreamController<PhotoViewControllerValue> _outputCtrl;
StreamController<PhotoViewScaleState> _outputScaleStateCtrl;

@override
Stream<PhotoViewControllerValue> get outputStateStream => _outputCtrl.stream;

@override
Stream<PhotoViewScaleState> get outputScaleStateStream =>
_outputScaleStateCtrl.stream;

@override
PhotoViewControllerValue prevValue;

@override
void reset() {
value = initial;
_outputScaleStateCtrl.sink.add(PhotoViewScaleState.initial);
}

void _changeListener() {
Expand All @@ -147,6 +159,7 @@ class PhotoViewController
@override
void dispose() {
_outputCtrl.close();
_outputScaleStateCtrl.close();
_notifier.dispose();
}

Expand All @@ -172,6 +185,7 @@ class PhotoViewController
if (value.scale == scale) {
return;
}

prevValue = value;
value = PhotoViewControllerValue(
position: position,
Expand Down Expand Up @@ -213,6 +227,7 @@ class PhotoViewController
rotation: rotation,
scaleState: scaleState,
rotationFocusPoint: rotationFocusPoint);
_outputScaleStateCtrl.sink.add(scaleState);
}

@override
Expand Down Expand Up @@ -245,6 +260,9 @@ class PhotoViewController
Size outerSize,
Size childSize,
}) {
if (value.scaleState != scaleState) {
_outputScaleStateCtrl.sink.add(scaleState);
}
prevValue = value;
value = PhotoViewControllerValue(
position: position ?? value.position,
Expand Down
17 changes: 12 additions & 5 deletions lib/src/photo_view_image_wrapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,15 @@ class _PhotoViewImageWrapperState extends State<PhotoViewImageWrapper>
void onScaleUpdate(ScaleUpdateDetails details) {
final double newScale = _scaleBefore * details.scale;
final Offset delta = details.focalPoint - _normalizedPosition;

final double _initialScale = widget.scaleBoundaries.initialScale;

final PhotoViewScaleState newScaleState = details.scale != 1.0
? PhotoViewScaleState.zooming
? (newScale > _initialScale)
? PhotoViewScaleState.zoomedIn
: PhotoViewScaleState.zoomedOut
: widget.controller.scaleState;

widget.controller.updateMultiple(
scaleState: newScaleState,
scale: newScale,
Expand Down Expand Up @@ -249,7 +255,8 @@ class _PhotoViewImageWrapperState extends State<PhotoViewImageWrapper>
void scaleStateListener(PhotoViewControllerValue value) {
if (widget.controller.prevValue.scaleState !=
widget.controller.scaleState &&
widget.controller.scaleState != PhotoViewScaleState.zooming) {
(widget.controller.scaleState != PhotoViewScaleState.zoomedIn &&
widget.controller.scaleState != PhotoViewScaleState.zoomedOut)) {
final double prevScale = widget.controller.scale ??
getScaleForScaleState(
PhotoViewScaleState.initial, widget.scaleBoundaries);
Expand All @@ -267,11 +274,11 @@ class _PhotoViewImageWrapperState extends State<PhotoViewImageWrapper>
final ScaleBoundaries scaleBoundaries = widget.scaleBoundaries;
final PhotoViewControllerBase controller = widget.controller;
final PhotoViewScaleState scaleState = controller.scaleState;
if (scaleState == PhotoViewScaleState.zooming) {
controller.scaleState = widget.scaleStateCycle(scaleState);
if (scaleState == PhotoViewScaleState.zoomedIn ||
scaleState == PhotoViewScaleState.zoomedOut) {
widget.controller.scaleState = widget.scaleStateCycle(scaleState);
return;
}

final double originalScale =
getScaleForScaleState(scaleState, scaleBoundaries);

Expand Down
8 changes: 7 additions & 1 deletion lib/src/photo_view_scale_state.dart
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
/// A way to represent the step of the "doubletap gesture cycle" in which PhotoView is.
enum PhotoViewScaleState { initial, covering, originalSize, zooming }
enum PhotoViewScaleState {
initial,
covering,
originalSize,
zoomedIn,
zoomedOut
}
3 changes: 2 additions & 1 deletion lib/src/photo_view_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ double getScaleForScaleState(
PhotoViewScaleState scaleState, ScaleBoundaries scaleBoundaries) {
switch (scaleState) {
case PhotoViewScaleState.initial:
case PhotoViewScaleState.zooming:
case PhotoViewScaleState.zoomedIn:
case PhotoViewScaleState.zoomedOut:
return _clampSize(scaleBoundaries.initialScale, scaleBoundaries);
case PhotoViewScaleState.covering:
return _clampSize(
Expand Down
18 changes: 11 additions & 7 deletions test/controller_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ void main() {
controller.rotationFocusPoint = Offset.zero;
expect(controller.rotationFocusPoint, Offset.zero);

controller.scaleState = PhotoViewScaleState.zooming;
expect(controller.scaleState, PhotoViewScaleState.zooming);
controller.scaleState = PhotoViewScaleState.zoomedIn;
expect(controller.scaleState, PhotoViewScaleState.zoomedIn);

// controller.scaleState = PhotoViewScaleState.zoomedOut;
// expect(controller.scaleState, PhotoViewScaleState.zoomedOut);

controller.updateMultiple(
position: const Offset(1, 1), scaleState: PhotoViewScaleState.initial);
Expand All @@ -63,35 +66,36 @@ void main() {
scale: null,
rotation: 0.0,
rotationFocusPoint: null,
scaleState: PhotoViewScaleState.zooming);
scaleState: PhotoViewScaleState.zoomedOut);

const PhotoViewControllerValue value2 = const PhotoViewControllerValue(
position: Offset.zero,
scale: null,
rotation: 1.0,
rotationFocusPoint: null,
scaleState: PhotoViewScaleState.zooming);
scaleState: PhotoViewScaleState.zoomedOut);

const PhotoViewControllerValue value3 = const PhotoViewControllerValue(
position: Offset.zero,
scale: 3.0,
rotation: 1.0,
rotationFocusPoint: null,
scaleState: PhotoViewScaleState.zooming);
scaleState: PhotoViewScaleState.zoomedOut);

const PhotoViewControllerValue value4 = const PhotoViewControllerValue(
position: const Offset(1, 1),
scale: 3.0,
rotation: 45.0,
rotationFocusPoint: null,
scaleState: PhotoViewScaleState.zooming);
scaleState: PhotoViewScaleState.zoomedOut);

expect(controller.outputStateStream,
emitsInOrder([value1, value2, value3, value4]));
controller.scaleState = PhotoViewScaleState.zooming;
controller.scaleState = PhotoViewScaleState.zoomedOut;
controller.rotation = 1.0;
controller.scale = 3.0;

controller.updateMultiple(position: const Offset(1, 1), rotation: 45.0);
//Testing with 'zoomedIn' and 'zoomedOut' will be diffcult as long as scaleState isn't changed in the controller's scale setter
});
}

0 comments on commit 99ec0c5

Please sign in to comment.