Skip to content

Commit

Permalink
version 0.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
maeddin committed Mar 12, 2022
1 parent 1c3b29e commit 1f83814
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 74 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.3.0 [2022-03-12]
- adds onTap parameter
- adds jump method to ActionSliderController
- minor gesture detection improvements

## 0.2.1 [2022-02-28]
- changes README.md

Expand Down
164 changes: 96 additions & 68 deletions lib/src/action_slider_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:action_slider/action_slider.dart';
import 'package:action_slider/src/cross_fade.dart';
import 'package:action_slider/src/mode.dart';
import 'package:action_slider/src/state.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

enum SliderBehavior { move, stretch }
Expand All @@ -13,9 +14,14 @@ typedef BackgroundBuilder = Widget Function(
typedef ForegroundBuilder = Widget Function(
BuildContext, ActionSliderState, Widget?);
typedef SlideCallback = Function(ActionSliderController controller);
typedef TapCallback = Function(ActionSliderController controller);

class ActionSliderController extends ValueNotifier<SliderMode> {
ActionSliderController() : super(SliderMode.standard);
class ActionSliderController extends ChangeNotifier
implements ValueListenable<SliderMode> {
SliderMode _value = SliderMode.standard;

@override
SliderMode get value => _value;

///Sets the state to success
void success() => _setMode(SliderMode.success);
Expand All @@ -29,12 +35,19 @@ class ActionSliderController extends ValueNotifier<SliderMode> {
///Sets the state to loading
void loading() => _setMode(SliderMode.loading);

///The Toggle jumps to [pos] which should be between 0.0 and 1.0.
void jump([double pos = 0.3]) => _setMode(SliderMode.jump(pos));

///Allows to define custom [SliderMode]s.
///This is useful for other results like success or failure.
///You get this modes in the [foregroundBuilder] of [ConfirmationSlider.custom] or in the [customForegroundBuilder] of [ConfirmationSlider.standard].
void custom(SliderMode mode) => _setMode(mode);

void _setMode(SliderMode mode) => value = mode;
void _setMode(SliderMode mode, {bool notify = true}) {
if (value == mode) return;
_value = mode;
if (notify) notifyListeners();
}
}

class ActionSlider extends StatefulWidget {
Expand Down Expand Up @@ -89,10 +102,17 @@ class ActionSlider extends StatefulWidget {
final BorderRadius backgroundBorderRadius;

///Callback for sliding completely to the right.
///Here you should call the loading, success and failure methods of the [controller] for controlling the further behaviour/animations of the slider.
///Optionally [onSlide] can be a [SlideCallback] for using the widget without an external controller.
///Here you should call the loading, success and failure methods of the
///[controller] for controlling the further behaviour/animations of the
///slider.
final SlideCallback? onSlide;

///Callback for tapping on the [ActionSlider]. Defaults to (c) => c.jump().
///Is only called if the toggle is currently not dragged.
///If you want onTap to be called in any case, you should wrap ActionSlider
///in a GestureDetector.
final TapCallback? onTap;

///Controller for controlling the widget from everywhere.
final ActionSliderController? controller;

Expand Down Expand Up @@ -130,8 +150,11 @@ class ActionSlider extends StatefulWidget {
)
],
this.sliderBehavior = SliderBehavior.move,
this.onTap = _defaultOnTap,
}) : super(key: key);

static _defaultOnTap(ActionSliderController c) => c.jump();

///Standard constructor for creating a Slider.
///If [customForegroundBuilder] is not null, the values of [successIcon], [failureIcon], [loadingIcon] and [icon] are ignored.
///This is useful if you use your own [SliderMode]s.
Expand All @@ -151,6 +174,7 @@ class ActionSlider extends StatefulWidget {
double circleRadius = 25.0,
bool rolling = false,
SlideCallback? onSlide,
TapCallback? onTap = _defaultOnTap,
ActionSliderController? controller,
double? width,
Duration slideAnimationDuration = const Duration(milliseconds: 250),
Expand Down Expand Up @@ -197,6 +221,7 @@ class ActionSlider extends StatefulWidget {
toggleHeight: circleRadius * 2,
backgroundColor: backgroundColor,
onSlide: onSlide,
onTap: onTap,
controller: controller,
width: width,
slideAnimationDuration: slideAnimationDuration,
Expand Down Expand Up @@ -281,7 +306,7 @@ class ActionSlider extends StatefulWidget {
child = successIcon;
} else if (mode == SliderMode.failure) {
child = failureIcon;
} else if (mode == SliderMode.standard) {
} else if (mode == SliderMode.standard || mode.isJump) {
child = rotating
? Transform.rotate(
angle: state.position * state.size.width / radius,
Expand Down Expand Up @@ -385,8 +410,14 @@ class _ActionSliderState extends State<ActionSlider>
if (_controller.value.expanded) {
_slideAnimationController.reverse();
_loadingAnimationController.reverse();
setState(() => state =
state.copyWith(releasePosition: 1.0, state: SlidingState.released));
if (_controller.value.jumpPosition > 0.0) {
_controller._setMode(SliderMode.standard, notify: false);
state = state.copyWith(releasePosition: 0.3);
_slideAnimationController.forward();
} else {
setState(() => state =
state.copyWith(releasePosition: 1.0, state: SlidingState.released));
}
} else {
_loadingAnimationController.forward();
setState(() => state =
Expand Down Expand Up @@ -429,49 +460,9 @@ class _ActionSliderState extends State<ActionSlider>
}

return GestureDetector(
onHorizontalDragStart: (details) {
final x = details.localPosition.dx;
if (x >= togglePosition && x <= toggleWidth) {
setState(() {
state = SliderState(
position: ((details.localPosition.dx -
frame -
widget.toggleWidth / 2) /
backgroundWidth)
.clamp(0.0, 1.0),
state: SlidingState.dragged,
);
});
}
},
onHorizontalDragUpdate: (details) {
if (state.state == SlidingState.dragged) {
double newPosition = ((details.localPosition.dx -
frame -
widget.toggleWidth / 2) /
backgroundWidth)
.clamp(0.0, 1.0);
setState(() {
state = SliderState(
position: newPosition,
state: newPosition < 1.0
? SlidingState.dragged
: SlidingState.released,
);
});
if (state.state == SlidingState.released) _onSlide();
}
},
onHorizontalDragEnd: (details) => setState(() {
state = state.copyWith(
state: SlidingState.released,
releasePosition: state.position);
_slideAnimationController.reverse(from: 1.0);
}),
onTap: () {
if (state.state != SlidingState.released) return;
state = state.copyWith(releasePosition: 0.3);
_slideAnimationController.forward();
widget.onTap?.call(_controller);
},
child: Container(
width: width,
Expand Down Expand Up @@ -508,26 +499,63 @@ class _ActionSliderState extends State<ActionSlider>
left: togglePosition,
width: toggleWidth,
height: widget.toggleHeight,
child: MouseRegion(
cursor: state.state == SlidingState.loading
? MouseCursor.defer
: (state.state == SlidingState.released
? SystemMouseCursors.grab
: SystemMouseCursors.grabbing),
child: Builder(
builder: (context) => widget.foregroundBuilder(
context,
ActionSliderState(
position: state.position,
size: Size(width, widget.height),
standardSize: Size(maxWidth, widget.height),
slidingState: state.state,
sliderMode: _controller.value,
releasePosition: state.releasePosition,
toggleSize:
Size(toggleWidth, widget.toggleHeight),
child: GestureDetector(
onHorizontalDragStart: (details) {
setState(() {
state = SliderState(
position: ((details.localPosition.dx -
widget.toggleWidth / 2) /
backgroundWidth)
.clamp(0.0, 1.0),
state: SlidingState.dragged,
);
});
},
onHorizontalDragUpdate: (details) {
if (state.state == SlidingState.dragged) {
double newPosition = ((details.localPosition.dx -
widget.toggleWidth / 2) /
backgroundWidth)
.clamp(0.0, 1.0);
setState(() {
state = SliderState(
position: newPosition,
state: newPosition < 1.0
? SlidingState.dragged
: SlidingState.released,
);
});
if (state.state == SlidingState.released)
_onSlide();
}
},
onHorizontalDragEnd: (details) => setState(() {
state = state.copyWith(
state: SlidingState.released,
releasePosition: state.position);
_slideAnimationController.reverse(from: 1.0);
}),
child: MouseRegion(
cursor: state.state == SlidingState.loading
? MouseCursor.defer
: (state.state == SlidingState.released
? SystemMouseCursors.grab
: SystemMouseCursors.grabbing),
child: Builder(
builder: (context) => widget.foregroundBuilder(
context,
ActionSliderState(
position: state.position,
size: Size(width, widget.height),
standardSize: Size(maxWidth, widget.height),
slidingState: state.state,
sliderMode: _controller.value,
releasePosition: state.releasePosition,
toggleSize:
Size(toggleWidth, widget.toggleHeight),
),
widget.foregroundChild,
),
widget.foregroundChild,
),
),
),
Expand Down
26 changes: 21 additions & 5 deletions lib/src/mode.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ class SliderMode {
final dynamic key;
final bool expanded;
final bool custom;
final double jumpPosition;

const SliderMode({required this.key, this.expanded = false}) : custom = true;
const SliderMode({required this.key, this.expanded = false})
: jumpPosition = 0.0,
custom = true;

const SliderMode._internal({required this.key, this.expanded = false})
: custom = false;
const SliderMode._internal({
required this.key,
this.expanded = false,
this.jumpPosition = 0.0,
}) : custom = false;

static const loading = SliderMode._internal(key: _SliderModeKey('loading'));
static const success = SliderMode._internal(key: _SliderModeKey('success'));
Expand All @@ -16,16 +22,26 @@ class SliderMode {
expanded: true,
);

bool get isJump => key == 'jump' && !custom;

const SliderMode.jump(double pos)
: this._internal(
key: 'jump',
expanded: true,
jumpPosition: pos,
);

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is SliderMode &&
runtimeType == other.runtimeType &&
key == other.key &&
custom == other.custom;
custom == other.custom &&
jumpPosition == other.jumpPosition;

@override
int get hashCode => key.hashCode ^ custom.hashCode;
int get hashCode => key.hashCode ^ custom.hashCode ^ jumpPosition.hashCode;
}

class _SliderModeKey {
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: action_slider
description: A slider to confirm actions and provide feedback on the success of these after subsequent loading.
version: 0.2.1
version: 0.3.0
repository: https://github.com/SplashByte/action_slider

environment:
Expand Down

0 comments on commit 1f83814

Please sign in to comment.