Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
3 changes: 3 additions & 0 deletions packages/rfw/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.0.27
* Adds `Slider` material widget

## 1.0.26
* Supports overriding the error widget builder.

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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be a space after the :?

return Slider(
value: value,
secondaryTrackValue: source.v<double>(['secondaryTrackValue']),
onChanged: source.handler(['onChanged'],
(HandlerTrigger trigger) => (double value) {
trigger({'value': value});
}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per the style guide, indentation should never have a line that is less indented than a line that is of higher lexical scope (well the style guide doesn't say it quite that way but that's the intent).

Suggested change
onChanged: source.handler(['onChanged'],
(HandlerTrigger trigger) => (double value) {
trigger({'value': value});
}),
onChanged: source.handler(['onChanged'],
(HandlerTrigger trigger) => (double value) {
trigger({'value': value});
},
),

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(same below)

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.26
version: 1.0.27

environment:
sdk: ^3.2.0
Expand Down
85 changes: 85 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,89 @@ 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 tester.slideToValue(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}'));
});
}
13 changes: 13 additions & 0 deletions packages/rfw/test/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'dart:io' show Platform;

import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';

// Detects if we're running the tests on the main channel.
//
Expand All @@ -21,3 +22,15 @@ bool get isMainChannel {

// See Contributing section of README.md file.
final bool runGoldens = !kIsWeb && Platform.isLinux && isMainChannel;

// slide to value for material slider in tests
extension SlideTo on WidgetTester {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you make this a function instead of an extension? that would make it easier to find when reading the code (otherwise it looks like you have to look on WidgetTester).

See also https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#avoid-using-extension

Future<void> slideToValue(Finder slider, double value,
{double paddingOffset = 24.0}) async {
final Offset zeroPoint =
getTopLeft(slider) + Offset(paddingOffset, getSize(slider).height / 2);
final double totalWidth = getSize(slider).width - (2 * paddingOffset);
final double calculateOffset = value * (totalWidth / 100);
await dragFrom(zeroPoint, Offset(calculateOffset, 0));
}
}