Skip to content

Commit 53cb139

Browse files
authored
Merge pull request #32 from do9core/feat/infinite-rolling
feat: implement roulette infinite scrolling behavior
2 parents 522a3d6 + 97fbfa6 commit 53cb139

10 files changed

Lines changed: 326 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# 0.3.2 - 2026/3/10
2+
3+
### New feature
4+
* You can now roll the Roulette infinitely with `rollInfinitely` method, until you call `rollTo` or `stop` method. The example is also updated to show how to use it.
5+
16
## 0.3.1 - 2026/3/9
27

38
### New feature

README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Add this to your `pubspec.yaml` file:
3535

3636
```yaml
3737
dependencies:
38-
roulette: ^0.3.1
38+
roulette: ^0.3.2
3939
```
4040
4141
## Usage
@@ -166,6 +166,26 @@ await controller.rollTo(
166166
);
167167
```
168168

169+
### Roll infinitely before determine the result (available in 0.3.2)
170+
171+
You can also use `rollInfinitely` to roll infinitely until you call `stop` or `rollTo` method:
172+
173+
```dart
174+
// Roll infinitely
175+
controller.rollInfinitely();
176+
177+
// Getting the result value somewhere...
178+
try {
179+
final result = await service.request()
180+
final index = values.indexOf(result);
181+
// Stop rolling and settle to index
182+
controller.rollTo(index, offset: random.nextDouble());
183+
} catch (e, st) {
184+
// Or stop rolling immediately, stop with this method has no animation
185+
// controller.stop();
186+
}
187+
```
188+
169189
Please refer to API documentation for more details.
170190

171191
For more complete examples, please check the example app.

example/lib/main.dart

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ class _HomePageState extends State<HomePage> {
251251
switch (_animationMode) {
252252
case AnimationMode.curve:
253253
config = const CurveAnimationConfig(
254-
curve: Curves.fastOutSlowIn,
254+
curve: Curves.easeOut,
255255
duration: Duration(seconds: 5),
256256
);
257257
case AnimationMode.physics:
@@ -278,19 +278,28 @@ class _HomePageState extends State<HomePage> {
278278
);
279279
}
280280
},
281-
child: const Text('ROLL'),
281+
child: const Text('Roll'),
282+
),
283+
FilledButton(
284+
onPressed: () {
285+
_controller.rollInfinitely(
286+
period: const Duration(milliseconds: 200),
287+
clockwise: _clockwise,
288+
);
289+
},
290+
child: Text('Roll Infinitely'),
282291
),
283292
FilledButton(
284293
onPressed: () {
285294
_controller.stop();
286295
},
287-
child: const Text('CANCEL'),
296+
child: const Text('Cancel'),
288297
),
289298
FilledButton(
290299
onPressed: () {
291300
_controller.resetAnimation();
292301
},
293-
child: const Text('RESET'),
302+
child: const Text('Reset'),
294303
),
295304
],
296305
),

example/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ packages:
198198
path: ".."
199199
relative: true
200200
source: path
201-
version: "0.3.0"
201+
version: "0.3.2"
202202
shared_preferences:
203203
dependency: transitive
204204
description:

lib/src/roulette.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ class RouletteState extends State<Roulette>
102102
_handleStop();
103103
} else if (event is RouletteResetEvent) {
104104
_handleReset();
105+
} else if (event is InfiniteRollEvent) {
106+
_handleInfiniteRoll(event);
105107
}
106108
}
107109

@@ -156,6 +158,22 @@ class RouletteState extends State<Roulette>
156158
.catchError((_) => _reportEvent(OnRollCancelledEvent(event)));
157159
}
158160

161+
void _handleInfiniteRoll(InfiniteRollEvent event) {
162+
if (_animationController.isAnimating) {
163+
_animationController.stop();
164+
}
165+
166+
rotateAnimation.value = makeInfiniteRollAnimation(
167+
_animationController,
168+
clockwise: event.clockwise,
169+
curve: event.curve,
170+
);
171+
_animationController
172+
.repeat(period: event.period)
173+
.orCancel
174+
.catchError((_) => _reportEvent(OnRollCancelledEvent(event)));
175+
}
176+
159177
void _handleStop() {
160178
_animationController.stop();
161179
}

lib/src/roulette_controller.dart

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,19 @@ class RouletteStopEvent implements RouletteEvent {
7979
const RouletteStopEvent();
8080
}
8181

82+
@internal
83+
class InfiniteRollEvent implements RouletteEvent {
84+
const InfiniteRollEvent({
85+
required this.clockwise,
86+
this.period = defaultPeriod,
87+
this.curve,
88+
});
89+
90+
final bool clockwise;
91+
final Duration period;
92+
final Curve? curve;
93+
}
94+
8295
@internal
8396
class RouletteResetEvent implements RouletteEvent {
8497
const RouletteResetEvent();
@@ -123,7 +136,12 @@ class RouletteController {
123136
_eventStreamController.add(RouletteResetEvent());
124137
}
125138

126-
/// Stop current running animation
139+
/// Stop current running animation.
140+
/// No animation will be performed, the roulette will
141+
/// stop at current position directly.
142+
///
143+
/// If you want your roulette to stop with an animation,
144+
/// use [rollTo] instead.
127145
void stop() {
128146
_eventStreamController.add(RouletteStopEvent());
129147
}
@@ -176,6 +194,35 @@ class RouletteController {
176194
return completer.future;
177195
}
178196

197+
/// Start rolling the roulette indefinitely until a
198+
/// [rollTo], [rollInfinitely] or [stop] is called.
199+
/// The [clockwise] determine whether the animator should run in clockwise direction.
200+
/// Config [period] to update the roll period for one circle.
201+
/// If you want to change the cycle animation behavior, try [curve],
202+
/// but it may make the animation look wired.
203+
///
204+
/// Returning a [Future], when the animation is completed(cancelled actually)
205+
/// the future resolved.
206+
Future<void> rollInfinitely({
207+
bool clockwise = true,
208+
Duration period = defaultPeriod,
209+
Curve? curve,
210+
}) {
211+
final completer = Completer<void>();
212+
final event = InfiniteRollEvent(clockwise: clockwise, period: period);
213+
_eventStreamController.add(event);
214+
215+
StreamSubscription? subscription;
216+
subscription = _callbackStreamController.stream.listen((e) {
217+
if (e is OnRollCancelledEvent && e.event == event) {
218+
completer.complete();
219+
subscription?.cancel();
220+
}
221+
});
222+
223+
return completer.future;
224+
}
225+
179226
void dispose() {
180227
_eventStreamController.close();
181228
_callbackStreamController.close();

lib/utils/constants.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ const int defaultMinRotateCircles = 12;
33

44
/// Default rotate animation run time
55
const Duration defaultDuration = Duration(seconds: 5);
6+
7+
/// Default infinite roll period
8+
const Duration defaultPeriod = Duration(seconds: 1);

lib/utils/helpers.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,24 @@ Animation<double> makeAnimation(
2323
}
2424
}
2525

26+
/// Make [Animation] from [controller] to begin infinite roll effect.
27+
Animation<double> makeInfiniteRollAnimation(
28+
AnimationController controller, {
29+
required bool clockwise,
30+
double initialValue = 0,
31+
Curve? curve,
32+
}) {
33+
final begin = initialValue % (2 * pi);
34+
final end = begin + 2 * pi * (clockwise ? 1 : -1);
35+
final tween = Tween(begin: begin, end: end);
36+
if (curve != null) {
37+
final curved = CurvedAnimation(parent: controller, curve: curve);
38+
return curved.drive(tween);
39+
} else {
40+
return controller.drive(tween);
41+
}
42+
}
43+
2644
/// Calculate the end rotate value by [targetIndex].
2745
/// The returned value contains the circles to roll.
2846
/// Make sure when you run this method the [group] has at least one [RouletteUnit].

pubspec.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
name: roulette
22
description: This is a library provide a simple roulette widget which usually used for lottery.
3-
version: 0.3.1
3+
version: 0.3.2
44
repository: https://github.com/do9core/roulette
5+
issue_tracker: https://github.com/do9core/roulette/issues
6+
topics:
7+
- widget
58

69
environment:
710
sdk: ">=2.12.0 <4.0.0"

0 commit comments

Comments
 (0)