Skip to content

Commit

Permalink
[rfw] Material slider widget (#6610)
Browse files Browse the repository at this point in the history
### Description
This adds Slider widget to material widgets.
  • Loading branch information
uberchilly authored Jun 5, 2024
1 parent 84fd510 commit 5183cac
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 1 deletion.
4 changes: 4 additions & 0 deletions packages/rfw/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.0.29

* Adds support for the `Slider` Material widget.

## 1.0.28

* Updates documentation to WidgetStateProperty and ButtonBar.
Expand Down
34 changes: 34 additions & 0 deletions packages/rfw/lib/src/flutter/material_widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import 'runtime.dart';
/// * [Material]
/// * [OutlinedButton]
/// * [Scaffold]
/// * [Slider]
/// * [TextButton]
/// * [VerticalDivider]
/// * [OverflowBar]
Expand Down Expand Up @@ -499,6 +500,39 @@ Map<String, LocalWidgetBuilder> get _materialWidgetsDefinitions => <String, Loca
);
},

'Slider': (BuildContext context, DataSource source) {
// not implemented: overlayColor, mouseCursor, semanticFormatterCallback, focusNode, autofocus
final min = source.v<double>(['min']) ?? 0.0;
final value = source.v<double>(['value']) ?? min;
final labelText = source.v<String>(['label']);
final label = labelText != null ? '$labelText: ${value.toStringAsFixed(2)}' : value.toStringAsFixed(2);
return Slider(
value: value,
secondaryTrackValue: source.v<double>(['secondaryTrackValue']),
onChanged: source.handler(['onChanged'],
(HandlerTrigger trigger) => (double value) {
trigger({'value': value});
}),
onChangeStart: source.handler(['onChangeStart'],
(HandlerTrigger trigger) => (double value) {
trigger({'value': value});
}),
onChangeEnd: source.handler(['onChangeEnd'],
(HandlerTrigger trigger) => (double value) {
trigger({'value': value});
}),
min: min,
max: source.v<double>(['max']) ?? 1.0,
divisions: source.v<int>(['divisions']),
label: label,
activeColor: ArgumentDecoders.color(source, ['activeColor']),
inactiveColor: ArgumentDecoders.color(source, ['inactiveColor']),
secondaryActiveColor: ArgumentDecoders.color(source, ['secondaryActiveColor']),
thumbColor: ArgumentDecoders.color(source, ['thumbColor']),
allowedInteraction: ArgumentDecoders.enumValue<SliderInteraction>(SliderInteraction.values, source, ['allowedInteraction']),
);
},

'TextButton': (BuildContext context, DataSource source) {
// not implemented: buttonStyle, focusNode
return TextButton(
Expand Down
2 changes: 1 addition & 1 deletion packages/rfw/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: rfw
description: "Remote Flutter widgets: a library for rendering declarative widget description files at runtime."
repository: https://github.com/flutter/packages/tree/main/packages/rfw
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+rfw%22
version: 1.0.28
version: 1.0.29

environment:
sdk: ^3.2.0
Expand Down
97 changes: 97 additions & 0 deletions packages/rfw/test/material_widgets_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -586,4 +586,101 @@ void main() {
expect(tester.widget<Material>(find.byType(Material)).clipBehavior,
Clip.antiAlias);
});

testWidgets('Slider properties', (WidgetTester tester) async {
final Runtime runtime = setupRuntime();
final DynamicContent data = DynamicContent();
final List<String> eventLog = <String>[];
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(useMaterial3: false),
home: RemoteWidget(
runtime: runtime,
data: data,
widget: const FullyQualifiedWidgetName(testName, 'root'),
onEvent: (String eventName, DynamicMap eventArguments) {
eventLog.add('$eventName $eventArguments');
},
),
),
);
expect(
tester.takeException().toString(),
contains('Could not find remote widget named'),
);

runtime.update(testName, parseLibraryFile('''
import core;
import material;
widget root = Scaffold(
body: Center(
child: Slider(
onChanged: event 'slider' { },
min: 10.0,
max: 100.0,
divisions: 100,
value: 20.0,
activeColor: 0xFF0000FF,
inactiveColor: 0xFF00FF00,
secondaryActiveColor: 0xFFFF0000,
thumbColor: 0xFF000000,
)));
'''));
await tester.pump();

final Finder sliderFinder = find.byType(Slider);
final Slider slider = tester.widget<Slider>(sliderFinder);
expect(slider.value, 20.0);
expect(slider.min, 10.0);
expect(slider.max, 100.0);
expect(slider.divisions, 100);
expect(slider.activeColor, const Color(0xFF0000FF));
expect(slider.inactiveColor, const Color(0xFF00FF00));
expect(slider.secondaryActiveColor, const Color(0xFFFF0000));
expect(slider.thumbColor, const Color(0xFF000000));

runtime.update(testName, parseLibraryFile('''
import core;
import material;
widget root = Scaffold(
body: Container(
child: Slider(
onChanged: event 'slider' { },
onChangeStart: event 'slider.start' { },
onChangeEnd: event 'slider.end' { },
min: 0.0,
max: 100.0,
divisions: 100,
value: 0.0,
)));
'''));
await tester.pump();

//drag slider
await _slideToValue(tester, sliderFinder, 20.0);
await tester.pumpAndSettle();
expect(eventLog,
contains(kIsWeb ? 'slider {value: 20}' : 'slider {value: 20.0}'));
expect(
eventLog,
contains(
kIsWeb ? 'slider.start {value: 0}' : 'slider.start {value: 0.0}'));
expect(
eventLog,
contains(
kIsWeb ? 'slider.end {value: 20}' : 'slider.end {value: 20.0}'));
});
}

// slide to value for material slider in tests
Future<void> _slideToValue(
WidgetTester widgetTester, Finder slider, double value,
{double paddingOffset = 24.0}) async {
final Offset zeroPoint = widgetTester.getTopLeft(slider) +
Offset(paddingOffset, widgetTester.getSize(slider).height / 2);
final double totalWidth =
widgetTester.getSize(slider).width - (2 * paddingOffset);
final double calculateOffset = value * (totalWidth / 100);
await widgetTester.dragFrom(zeroPoint, Offset(calculateOffset, 0));
}

0 comments on commit 5183cac

Please sign in to comment.