Skip to content

Commit cbc52ec

Browse files
committed
Slider: fader thumb, end fill, notches, marker, selectable range, changeEnd
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AjsYaRkTHNKszSHjd3j264
1 parent 79abf2c commit cbc52ec

5 files changed

Lines changed: 266 additions & 1 deletion

File tree

‎lib/src/api/models/trigger.dart‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ enum TriggerType {
4545
/// Triggered when the canvas is loaded.
4646
load,
4747

48+
/// Triggered when the user lets go of a slider after changing it, with
49+
/// the final value. [changed] fires on every step of the drag.
50+
changeEnd,
51+
4852
/// Triggered repeatedly while the canvas is shown, every
4953
/// [TriggerModel.intervalMillis] milliseconds. Live readouts, countdowns
5054
/// and polling use it.
@@ -79,6 +83,8 @@ enum TriggerType {
7983
return 'Load';
8084
case TriggerType.interval:
8185
return 'Interval';
86+
case TriggerType.changeEnd:
87+
return 'Change End';
8288
}
8389
}
8490
}

‎lib/src/api/models/trigger.g.dart‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎lib/src/api/nodes/slider_node.dart‎

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,25 @@ const ColorRGBA kSliderDefaultInactiveTrackColor = ColorRGBA(
3939
/// Default opacity of slider's overlay.
4040
const double kSliderDefaultOverlayOpacity = 0.12;
4141

42+
/// The shape of a slider's thumb.
43+
enum SliderThumbShapeEnum {
44+
/// A circle of [SliderProperties.thumbRadius].
45+
circle,
46+
47+
/// A [SliderProperties.thumbWidth] × [SliderProperties.thumbHeight]
48+
/// rounded rectangle, like a fader knob.
49+
rectangle,
50+
}
51+
52+
/// How a slider draws the marks at its divisions.
53+
enum SliderTickMarkStyle {
54+
/// Dots on the track.
55+
dot,
56+
57+
/// Short lines below the track, longer at every fifth mark.
58+
notch,
59+
}
60+
4261
/// Slider is a widget that lets the user select a value from a given range.
4362
/// Refer to [Slider](https://api.flutter.dev/flutter/material/Slider-class.html)
4463
/// in Flutter for more details.
@@ -50,6 +69,11 @@ class SliderNode extends SceneNode with CustomPropertiesMixin {
5069
/// Currently selected value of slider.
5170
double value;
5271

72+
/// Where a thin marker sits on the track, e.g. the current reading next
73+
/// to an alarm limit the slider sets. No marker when null. Bindable as
74+
/// `markerValue`.
75+
double? markerValue;
76+
5377
/// Holds configurable properties of the slider.
5478
@override
5579
covariant SliderProperties properties;
@@ -79,6 +103,7 @@ class SliderNode extends SceneNode with CustomPropertiesMixin {
79103
required super.name,
80104
required super.basicBoxLocal,
81105
required this.value,
106+
this.markerValue,
82107
super.outerBoxLocal,
83108
super.retainedOuterBoxLocal,
84109
super.visible,
@@ -114,12 +139,17 @@ class SliderNode extends SceneNode with CustomPropertiesMixin {
114139
};
115140

116141
@override
117-
List<TriggerType> get triggerTypes => [TriggerType.changed];
142+
List<TriggerType> get triggerTypes => [
143+
TriggerType.changed,
144+
TriggerType.changeEnd,
145+
];
118146

119147
@override
120148
late final List<ValueModel> propertyVariables = [
121149
...super.propertyVariables,
122150
DoubleValue(name: 'value', value: value),
151+
DoubleValue(name: 'markerValue', value: markerValue ?? 0),
152+
ColorValue(name: 'activeTrackColor', value: properties.activeTrackColor),
123153
];
124154

125155
/// Creates a [SliderNode] instance from a JSON object.
@@ -224,6 +254,56 @@ class SliderProperties extends CustomProperties with FieldsHolder {
224254
/// room for the thumb's overlay. Mirrors `Slider.padding`.
225255
EdgeInsetsModel? padding;
226256

257+
/// The thumb's shape.
258+
SliderThumbShapeEnum thumbShape;
259+
260+
/// Width of a rectangle thumb.
261+
double thumbWidth;
262+
263+
/// Height of a rectangle thumb.
264+
double thumbHeight;
265+
266+
/// Corner radius of a rectangle thumb.
267+
double thumbCornerRadius;
268+
269+
/// Border drawn around the thumb. Transparent for none.
270+
ColorRGBA thumbBorderColor;
271+
272+
/// Width of [thumbBorderColor].
273+
double thumbBorderWidth;
274+
275+
/// Color of a short grip line across a rectangle thumb. Transparent for
276+
/// none.
277+
ColorRGBA thumbGripColor;
278+
279+
/// Whether the active track runs from the thumb to the end instead of
280+
/// from the start to the thumb, e.g. to shade the "above the limit" zone.
281+
bool fillFromEnd;
282+
283+
/// How division marks are drawn.
284+
SliderTickMarkStyle tickMarkStyle;
285+
286+
/// Draw a notch only at every this many divisions, e.g. 2 for a notch
287+
/// every 10% on a slider that snaps every 5%. Every fifth notch drawn is a
288+
/// long one.
289+
int notchEvery;
290+
291+
/// Color of the [SliderNode.markerValue] marker.
292+
ColorRGBA markerColor;
293+
294+
/// Width of the marker.
295+
double markerWidth;
296+
297+
/// Height of the marker, centered on the track.
298+
double markerHeight;
299+
300+
/// The lowest value the thumb can be dragged to, when the track's range
301+
/// ([min] to [max]) is wider than what may be picked. Null for [min].
302+
double? selectableMin;
303+
304+
/// The highest value the thumb can be dragged to. Null for [max].
305+
double? selectableMax;
306+
227307
/// Creates a [SliderProperties] instance with the given data.
228308
SliderProperties({
229309
this.activeTrackColor = ColorRGBA.black,
@@ -255,6 +335,21 @@ class SliderProperties extends CustomProperties with FieldsHolder {
255335
this.secondaryTrackValue,
256336
this.secondaryActiveTrackColor,
257337
this.padding,
338+
this.thumbShape = SliderThumbShapeEnum.circle,
339+
this.thumbWidth = 14,
340+
this.thumbHeight = 24,
341+
this.thumbCornerRadius = 2,
342+
this.thumbBorderColor = ColorRGBA.transparent,
343+
this.thumbBorderWidth = 2,
344+
this.thumbGripColor = ColorRGBA.transparent,
345+
this.fillFromEnd = false,
346+
this.tickMarkStyle = SliderTickMarkStyle.dot,
347+
this.notchEvery = 1,
348+
this.markerColor = ColorRGBA.white,
349+
this.markerWidth = 2,
350+
this.markerHeight = 14,
351+
this.selectableMin,
352+
this.selectableMax,
258353
});
259354

260355
/// Duplicates this [SliderProperties] instance with the given data
@@ -289,6 +384,21 @@ class SliderProperties extends CustomProperties with FieldsHolder {
289384
double? secondaryTrackValue,
290385
ColorRGBA? secondaryActiveTrackColor,
291386
EdgeInsetsModel? padding,
387+
SliderThumbShapeEnum? thumbShape,
388+
double? thumbWidth,
389+
double? thumbHeight,
390+
double? thumbCornerRadius,
391+
ColorRGBA? thumbBorderColor,
392+
double? thumbBorderWidth,
393+
ColorRGBA? thumbGripColor,
394+
bool? fillFromEnd,
395+
SliderTickMarkStyle? tickMarkStyle,
396+
int? notchEvery,
397+
ColorRGBA? markerColor,
398+
double? markerWidth,
399+
double? markerHeight,
400+
double? selectableMin,
401+
double? selectableMax,
292402
}) {
293403
return SliderProperties(
294404
activeTrackColor: activeTrackColor ?? this.activeTrackColor,
@@ -326,6 +436,21 @@ class SliderProperties extends CustomProperties with FieldsHolder {
326436
secondaryActiveTrackColor:
327437
secondaryActiveTrackColor ?? this.secondaryActiveTrackColor,
328438
padding: padding ?? this.padding,
439+
thumbShape: thumbShape ?? this.thumbShape,
440+
thumbWidth: thumbWidth ?? this.thumbWidth,
441+
thumbHeight: thumbHeight ?? this.thumbHeight,
442+
thumbCornerRadius: thumbCornerRadius ?? this.thumbCornerRadius,
443+
thumbBorderColor: thumbBorderColor ?? this.thumbBorderColor,
444+
thumbBorderWidth: thumbBorderWidth ?? this.thumbBorderWidth,
445+
thumbGripColor: thumbGripColor ?? this.thumbGripColor,
446+
fillFromEnd: fillFromEnd ?? this.fillFromEnd,
447+
tickMarkStyle: tickMarkStyle ?? this.tickMarkStyle,
448+
notchEvery: notchEvery ?? this.notchEvery,
449+
markerColor: markerColor ?? this.markerColor,
450+
markerWidth: markerWidth ?? this.markerWidth,
451+
markerHeight: markerHeight ?? this.markerHeight,
452+
selectableMin: selectableMin ?? this.selectableMin,
453+
selectableMax: selectableMax ?? this.selectableMax,
329454
);
330455
}
331456

@@ -561,6 +686,21 @@ class SliderProperties extends CustomProperties with FieldsHolder {
561686
secondaryTrackValue,
562687
secondaryActiveTrackColor,
563688
padding,
689+
thumbShape,
690+
thumbWidth,
691+
thumbHeight,
692+
thumbCornerRadius,
693+
thumbBorderColor,
694+
thumbBorderWidth,
695+
thumbGripColor,
696+
fillFromEnd,
697+
tickMarkStyle,
698+
notchEvery,
699+
markerColor,
700+
markerWidth,
701+
markerHeight,
702+
selectableMin,
703+
selectableMax,
564704
];
565705

566706
/// Creates a [SliderProperties] instance from a JSON object.

‎lib/src/api/nodes/slider_node.g.dart‎

Lines changed: 75 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import 'package:codelessly_api/codelessly_api.dart';
2+
import 'package:test/test.dart';
3+
4+
void main() {
5+
test('slider marker, fader thumb, notches and range round-trip', () {
6+
final node = SliderNode(
7+
id: 's',
8+
name: 'Limit',
9+
basicBoxLocal: NodeBox(0, 0, 300, 32),
10+
value: 75,
11+
markerValue: 87,
12+
properties: SliderProperties(
13+
thumbShape: SliderThumbShapeEnum.rectangle,
14+
thumbWidth: 14,
15+
thumbHeight: 24,
16+
thumbBorderColor: ColorRGBA.black,
17+
thumbGripColor: ColorRGBA.black,
18+
fillFromEnd: true,
19+
tickMarkStyle: SliderTickMarkStyle.notch,
20+
notchEvery: 2,
21+
markerColor: ColorRGBA.white,
22+
selectableMin: 5,
23+
selectableMax: 95,
24+
),
25+
);
26+
final back = NodeJsonConverter.instance.fromJson(node.toJson()) as SliderNode;
27+
expect(back.markerValue, 87);
28+
expect(back.properties, node.properties);
29+
expect(back.triggerTypes, contains(TriggerType.changeEnd));
30+
});
31+
32+
test('a slider from before keeps its defaults', () {
33+
final json = SliderNode(
34+
id: 's',
35+
name: 's',
36+
basicBoxLocal: NodeBox(0, 0, 300, 48),
37+
value: 1,
38+
properties: SliderProperties(),
39+
).toJson();
40+
expect(json.containsKey('markerValue'), isFalse);
41+
expect((json['properties'] as Map).containsKey('thumbShape'), isFalse);
42+
});
43+
}

0 commit comments

Comments
 (0)