Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UNLOCK image if image is zoomedOut #124

Merged
merged 7 commits into from
Apr 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]
renancaraujo marked this conversation as resolved.
Show resolved Hide resolved
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
});
}