feat: introduce _SpacingWidget for conditional spacing in SDUIFormWidget, enhance visibility handling with reactive updates, and improve error handling for child widgets
This commit is contained in:
@@ -30,6 +30,101 @@ class _StepperInfo {
|
||||
});
|
||||
}
|
||||
|
||||
// Helper widget that adds spacing only if previous widget is visible
|
||||
class _SpacingWidget extends StatelessWidget {
|
||||
final double spacing;
|
||||
final String? previousVisibleCondition;
|
||||
final RxMap<String, dynamic>? state;
|
||||
|
||||
const _SpacingWidget({
|
||||
required this.spacing,
|
||||
required this.previousVisibleCondition,
|
||||
required this.state,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// If previous widget has no visible condition, it's always visible
|
||||
if (previousVisibleCondition == null || previousVisibleCondition!.isEmpty) {
|
||||
return SizedBox(height: spacing);
|
||||
}
|
||||
|
||||
// Use Obx to reactively check if previous widget is visible
|
||||
return Obx(() {
|
||||
final isPreviousVisible = _evaluateVisibleConditionStatic(
|
||||
previousVisibleCondition!,
|
||||
state,
|
||||
);
|
||||
|
||||
if (isPreviousVisible) {
|
||||
return SizedBox(height: spacing);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Static version of _evaluateVisibleCondition for use in helper widget
|
||||
bool _evaluateVisibleConditionStatic(
|
||||
String condition,
|
||||
RxMap<String, dynamic>? state,
|
||||
) {
|
||||
if (state == null) {
|
||||
if (condition.contains('activeStepperIndex == 0')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// Simple condition evaluation
|
||||
// Supports: variable == value
|
||||
|
||||
if (condition.contains(' == ')) {
|
||||
final parts = condition.split(' == ');
|
||||
if (parts.length == 2) {
|
||||
final variable = parts[0].trim();
|
||||
var value = parts[1].trim();
|
||||
|
||||
// Remove quotes if present
|
||||
if ((value.startsWith("'") && value.endsWith("'")) ||
|
||||
(value.startsWith('"') && value.endsWith('"'))) {
|
||||
value = value.substring(1, value.length - 1);
|
||||
}
|
||||
|
||||
final stateValue = state[variable];
|
||||
if (stateValue == null) {
|
||||
// If variable doesn't exist in state, default to showing first step (0)
|
||||
if (variable == 'activeStepperIndex' && value == '0') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle int comparison
|
||||
final intValue = int.tryParse(value);
|
||||
if (intValue != null) {
|
||||
if (stateValue is int) {
|
||||
return stateValue == intValue;
|
||||
}
|
||||
if (stateValue is num) {
|
||||
return stateValue.toInt() == intValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle string comparison
|
||||
return stateValue.toString() == value;
|
||||
}
|
||||
}
|
||||
|
||||
// If condition format is not recognized, return false
|
||||
return false;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SDUIFormWidget extends StatelessWidget {
|
||||
final SDUIWidgetModel model;
|
||||
final Map<String, TextEditingController>? controllers;
|
||||
@@ -187,15 +282,25 @@ class SDUIFormWidget extends StatelessWidget {
|
||||
if (visibleCondition.contains('activeStepperIndex == 0')) {
|
||||
return builder();
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
return Visibility(
|
||||
visible: false,
|
||||
maintainSize: false,
|
||||
maintainState: false,
|
||||
maintainAnimation: false,
|
||||
child: builder(),
|
||||
);
|
||||
}
|
||||
|
||||
// Use Obx for reactive updates
|
||||
return Obx(() {
|
||||
if (!_evaluateVisibleCondition(visibleCondition)) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return builder();
|
||||
final isVisible = _evaluateVisibleCondition(visibleCondition);
|
||||
return Visibility(
|
||||
visible: isVisible,
|
||||
maintainSize: false,
|
||||
maintainState: false,
|
||||
maintainAnimation: false,
|
||||
child: builder(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -316,7 +421,6 @@ class SDUIFormWidget extends StatelessWidget {
|
||||
double paddingVertical,
|
||||
) {
|
||||
if (children.isEmpty) {
|
||||
iLog('Column has no children');
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
@@ -328,31 +432,84 @@ class SDUIFormWidget extends StatelessWidget {
|
||||
crossAxisAlignment,
|
||||
);
|
||||
|
||||
final builtChildren = children.map((child) {
|
||||
// Build all children first and extract their visible conditions
|
||||
final builtChildren = <Widget>[];
|
||||
final visibleConditions = <String?>[];
|
||||
|
||||
for (final child in children) {
|
||||
try {
|
||||
return _buildWidget(child);
|
||||
// Extract visible_condition from child model
|
||||
final visibleCondition = child.maybeWhen(
|
||||
column:
|
||||
(
|
||||
children,
|
||||
spacing,
|
||||
mainAxisSize,
|
||||
crossAxisAlignment,
|
||||
paddingHorizontal,
|
||||
paddingVertical,
|
||||
visible,
|
||||
visibleCondition,
|
||||
) => visibleCondition,
|
||||
row:
|
||||
(
|
||||
children,
|
||||
spacing,
|
||||
mainAxisAlignment,
|
||||
visible,
|
||||
visibleCondition,
|
||||
) => visibleCondition,
|
||||
cardLabelItem: (data, child, children, visible, visibleCondition) =>
|
||||
visibleCondition,
|
||||
stepper: (data, children, visible, visibleCondition) =>
|
||||
visibleCondition,
|
||||
textFormField: (data, visible, visibleCondition) =>
|
||||
visibleCondition,
|
||||
chipSelection: (data, visible, visibleCondition) =>
|
||||
visibleCondition,
|
||||
dropdown: (data, visible, visibleCondition) => visibleCondition,
|
||||
imagePicker: (data, visible, visibleCondition) => visibleCondition,
|
||||
pageView: (data, children, visible, visibleCondition) =>
|
||||
visibleCondition,
|
||||
sizedBox: (width, height, visible, visibleCondition) =>
|
||||
visibleCondition,
|
||||
orElse: () => null,
|
||||
);
|
||||
|
||||
visibleConditions.add(visibleCondition);
|
||||
builtChildren.add(_buildWidget(child));
|
||||
} catch (e) {
|
||||
iLog('Error building column child: $e');
|
||||
return Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
color: Colors.yellow.withAlpha(10),
|
||||
child: Text('Child Error'),
|
||||
visibleConditions.add(null);
|
||||
builtChildren.add(
|
||||
Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
color: Colors.yellow.withAlpha(10),
|
||||
child: Text('Child Error'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}).toList();
|
||||
}
|
||||
|
||||
// Add spacing between children
|
||||
final columnChildren = spacing > 0 && builtChildren.length > 1
|
||||
? <Widget>[]
|
||||
: builtChildren;
|
||||
// Wrap each child (except first) with spacing that only shows if previous child is visible
|
||||
final columnChildren = <Widget>[];
|
||||
|
||||
if (spacing > 0 && builtChildren.length > 1) {
|
||||
for (int i = 0; i < builtChildren.length; i++) {
|
||||
columnChildren.add(builtChildren[i]);
|
||||
if (i < builtChildren.length - 1) {
|
||||
columnChildren.add(SizedBox(height: spacing));
|
||||
}
|
||||
for (int i = 0; i < builtChildren.length; i++) {
|
||||
final widget = builtChildren[i];
|
||||
|
||||
if (i > 0 && spacing > 0) {
|
||||
// Add spacing that will be removed if previous widget is invisible
|
||||
// Use the visible_condition of the previous widget
|
||||
columnChildren.add(
|
||||
_SpacingWidget(
|
||||
spacing: spacing,
|
||||
previousVisibleCondition: visibleConditions[i - 1],
|
||||
state: state,
|
||||
),
|
||||
);
|
||||
}
|
||||
columnChildren.add(widget);
|
||||
}
|
||||
|
||||
final column = Column(
|
||||
@@ -849,6 +1006,8 @@ class SDUIFormWidget extends StatelessWidget {
|
||||
'sdui_form_stepper_${stepperInfo.stepperData.key ?? 'default'}';
|
||||
SDUIFormWidgetController formController;
|
||||
|
||||
fLog('mj ==>build With Stepper Layout');
|
||||
|
||||
try {
|
||||
formController = Get.find<SDUIFormWidgetController>(tag: controllerTag);
|
||||
} catch (_) {
|
||||
@@ -931,6 +1090,7 @@ class SDUIFormWidget extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
spacing: 30.h,
|
||||
children: contentWidgets,
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user