Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Range slider #1723

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
44 changes: 34 additions & 10 deletions modules/ensemble/lib/util/utils.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
import 'dart:io';
import 'dart:math';
import 'dart:ui';
import 'package:ensemble/ensemble.dart';
import 'package:ensemble/ensemble_app.dart';
import 'package:ensemble/framework/stub/location_manager.dart';
import 'package:ensemble/framework/theme/theme_manager.dart';
import 'package:ensemble_ts_interpreter/invokables/UserLocale.dart';
import 'package:path/path.dart' as p;

import 'package:ensemble/ensemble.dart';
import 'package:ensemble/framework/error_handling.dart';
import 'package:ensemble/framework/extensions.dart';
import 'package:ensemble/framework/model.dart';
import 'package:ensemble/framework/scope.dart';
import 'package:ensemble/framework/stub/location_manager.dart';
import 'package:ensemble/framework/theme/theme_manager.dart';
import 'package:ensemble/widget/helpers/controllers.dart';
import 'package:ensemble_ts_interpreter/invokables/UserLocale.dart';
import 'package:ensemble_ts_interpreter/invokables/invokableprimitives.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:path/path.dart' as p;
import 'package:yaml/yaml.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

rmahmadkhan marked this conversation as resolved.
Show resolved Hide resolved
class Utils {
/// global appKey to get the context
Expand Down Expand Up @@ -77,6 +74,32 @@ class Utils {
return rtn;
}

/// Expects a number or a String containing 2 numbers values separated by whitespace
/// (e.g. 1 or "1 4")
static RangeValues? getRangeValues(dynamic value) {
if (value is num) {
final start = optionalDouble(value);
if (start != null) {
return RangeValues(start, start);
}
} else if (value is String) {
final List<String> valuesList = value.split(RegExp('\\s+'));
if (valuesList.length == 1) {
final start = optionalDouble(valuesList[0]);
if (start != null) {
return RangeValues(start, start);
}
} else if (valuesList.length == 2) {
final start = optionalDouble(valuesList[0]);
final end = optionalDouble(valuesList[1]);
if (start != null && end != null) {
return RangeValues(start, end);
}
}
}
return null;
}

/// expect a value in seconds
static Duration? getDuration(dynamic value) {
double? number = optionalDouble(value, min: 0);
Expand Down Expand Up @@ -549,7 +572,8 @@ class Utils {
decorationStyle:
TextDecorationStyle.values.from(style['decorationStyle']),
decorationColor: Utils.getColor(style['decorationColor']),
decorationThickness: Utils.optionalDouble(style['decorationThickness']),
decorationThickness:
Utils.optionalDouble(style['decorationThickness']),
overflow: TextOverflow.values.from(style['overflow']),
letterSpacing: Utils.optionalDouble(style['letterSpacing']),
wordSpacing: Utils.optionalDouble(style['wordSpacing']));
Expand Down
93 changes: 63 additions & 30 deletions modules/ensemble/lib/widget/input/slider.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import 'package:ensemble/widget/helpers/input_wrapper.dart';
import 'package:flutter/material.dart';
import 'package:ensemble/framework/action.dart';
import 'package:ensemble/framework/event.dart';
import 'package:ensemble/screen_controller.dart';
import 'package:ensemble/util/utils.dart';
import 'package:ensemble/widget/helpers/form_helper.dart';
import 'package:ensemble/widget/helpers/widgets.dart';
import 'package:ensemble/widget/helpers/input_wrapper.dart';
import 'package:ensemble_ts_interpreter/invokables/invokable.dart';
import 'package:ensemble/util/utils.dart';
import 'package:ensemble/screen_controller.dart';
import 'package:flutter/material.dart';

class EnsembleSlider extends StatefulWidget
with Invokable, HasController<SliderController, SliderState> {
Expand Down Expand Up @@ -36,8 +35,8 @@ class EnsembleSlider extends StatefulWidget
@override
Map<String, Function> setters() {
return {
'initialValue': (value) =>
_controller.value = Utils.optionalDouble(value) ?? 0,
'initialValue': (value) => _controller.value =
Utils.getRangeValues(value) ?? const RangeValues(0, 0),
'min': (value) =>
Copy link
Member

Choose a reason for hiding this comment

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

The getter implementation for RangeValues needs to expose the individual start and end values since returning only the RangeValues object doesn't allow direct access to these values.

Copy link
Collaborator Author

@rmahmadkhan rmahmadkhan Nov 16, 2024

Choose a reason for hiding this comment

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

I intentionally did not do that. Since we are using RangeValue for for both, a user can get start or end value through value.
A thing we can do instead is add another getter in value which returns single value if start === end.

_controller.minValue = Utils.getDouble(value, fallback: 0.0),
'max': (value) =>
Expand All @@ -58,12 +57,14 @@ class EnsembleSlider extends StatefulWidget
_controller.trackHeight = Utils.optionalDouble(value),
'thumbRadius': (value) =>
_controller.thumbRadius = Utils.getDouble(value, fallback: 10),
'isRange': (value) =>
_controller.isRange = Utils.getBool(value, fallback: false),
};
}
}

class SliderController extends FormFieldController {
double value = 0.0;
RangeValues value = const RangeValues(0.0, 1.0);
double minValue = 0.0;
double maxValue = 1.0;
int? divisions;
Expand All @@ -77,6 +78,8 @@ class SliderController extends FormFieldController {

double? trackHeight;
double thumbRadius = 10;

bool isRange = false;
}

int calculateDecimalPlaces(double min, double max, int? divisions) {
Expand Down Expand Up @@ -104,7 +107,8 @@ class SliderState extends FormFieldWidgetState<EnsembleSlider> {
key: validatorKey,
validator: (value) {
if (widget._controller.required &&
widget.controller.value == widget.controller.minValue) {
widget.controller.value.start == widget.controller.minValue &&
widget.controller.value.end == widget.controller.minValue) {
return Utils.translateWithFallback(
'ensemble.input.required', 'This field is required');
}
Expand All @@ -124,27 +128,56 @@ class SliderState extends FormFieldWidgetState<EnsembleSlider> {
trackHeight: widget.controller.trackHeight,
valueIndicatorColor: widget.controller.thumbColor,
),
child: Slider(
label: widget.controller.value.toStringAsFixed(decimalPlaces),
min: widget.controller.minValue,
max: widget.controller.maxValue,
value: widget.controller.value,
divisions: widget.controller.divisions,
onChanged: isEnabled()
? (value) {
setState(() {
widget.controller.value = value;
});
if (widget.controller.onChange != null) {
ScreenController().executeAction(
context,
widget.controller.onChange!,
event: EnsembleEvent(widget),
);
}
}
: null,
),
child: widget.controller.isRange
? RangeSlider(
labels: RangeLabels(
widget.controller.value.start
.toStringAsFixed(decimalPlaces),
widget.controller.value.end
.toStringAsFixed(decimalPlaces),
),
min: widget.controller.minValue,
max: widget.controller.maxValue,
values: widget.controller.value,
divisions: widget.controller.divisions,
onChanged: isEnabled()
? (value) {
setState(() {
widget.controller.value = value;
});
if (widget.controller.onChange != null) {
ScreenController().executeAction(
context,
widget.controller.onChange!,
event: EnsembleEvent(widget),
);
}
}
: null,
)
: Slider(
label: widget.controller.value.start
.toStringAsFixed(decimalPlaces),
min: widget.controller.minValue,
max: widget.controller.maxValue,
value: widget.controller.value.start,
divisions: widget.controller.divisions,
onChanged: isEnabled()
? (value) {
setState(() {
widget.controller.value =
RangeValues(value, value);
});
if (widget.controller.onChange != null) {
ScreenController().executeAction(
context,
widget.controller.onChange!,
event: EnsembleEvent(widget),
);
}
}
: null,
),
);
Copy link
Member

Choose a reason for hiding this comment

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

Please remove the duplicate code which can be converted to method and use them.

Copy link
Collaborator Author

@rmahmadkhan rmahmadkhan Nov 16, 2024

Choose a reason for hiding this comment

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

Moved whole onChanged function to a separate function

},
),
Expand Down
18 changes: 9 additions & 9 deletions modules/ensemble/lib/widget/widget_registry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,17 @@ import 'package:ensemble/layout/tab_bar.dart';
import 'package:ensemble/layout/toggle_container.dart';
import 'package:ensemble/module/location_module.dart';
import 'package:ensemble/widget/Toggle.dart';
import 'package:ensemble/widget/accordion.dart';
import 'package:ensemble/widget/address.dart';
import 'package:ensemble/widget/avatar.dart';
import 'package:ensemble/widget/button.dart';
import 'package:ensemble/widget/calendar.dart';
import 'package:ensemble/widget/checkbox.dart';
import 'package:ensemble/widget/countdown.dart';
import 'package:ensemble/widget/radio/radio_button.dart';
import 'package:ensemble/widget/radio/radio_group.dart';
import 'package:ensemble/widget/static_map.dart';
import 'package:ensemble/widget/shape.dart';
import 'package:ensemble/widget/carousel.dart';
import 'package:ensemble/widget/chart_highcharts_builder.dart';
import 'package:ensemble/widget/checkbox.dart';
import 'package:ensemble/widget/conditional.dart';
import 'package:ensemble/widget/confirmation_input.dart';
import 'package:ensemble/widget/countdown.dart';
import 'package:ensemble/widget/divider.dart';
import 'package:ensemble/widget/ensemble_icon.dart';
import 'package:ensemble/widget/fintech/finicityconnect/finicityconnect.dart';
Expand All @@ -51,25 +48,28 @@ import 'package:ensemble/widget/markdown.dart';
import 'package:ensemble/widget/popup_menu.dart';
import 'package:ensemble/widget/progress_indicator.dart';
import 'package:ensemble/widget/qr_code.dart';
import 'package:ensemble/widget/radio/radio_button.dart';
import 'package:ensemble/widget/radio/radio_group.dart';
import 'package:ensemble/widget/rating.dart';
import 'package:ensemble/widget/shape.dart';
import 'package:ensemble/widget/signature.dart';
import 'package:ensemble/widget/slidable.dart';
import 'package:ensemble/widget/spacer.dart';
import 'package:ensemble/widget/staggered_grid.dart';
import 'package:ensemble/widget/static_map.dart';
import 'package:ensemble/widget/stub_widgets.dart';
import 'package:ensemble/widget/switch.dart';
import 'package:ensemble/widget/text.dart';
import 'package:ensemble/widget/toggle_button.dart';
import 'package:ensemble/widget/tooltip.dart';
import 'package:ensemble/widget/video.dart';
import 'package:ensemble/widget/slidable.dart';
import 'package:ensemble/widget/accordion.dart';
import 'package:ensemble/widget/visualization/barchart.dart';
import 'package:ensemble/widget/visualization/chart_js/chart_js.dart';
import 'package:ensemble/widget/visualization/line_area_chart.dart';
import 'package:ensemble/widget/visualization/topology_chart.dart';
import 'package:ensemble/widget/webview/webview.dart';
import 'package:ensemble/widget/youtube/youtube.dart';
import 'package:ensemble/widget/weeklyscheduler.dart';
import 'package:ensemble/widget/youtube/youtube.dart';
rmahmadkhan marked this conversation as resolved.
Show resolved Hide resolved
import 'package:get_it/get_it.dart';

import 'fintech/tabapayconnect.dart';
Expand Down
Loading