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:
2026-01-04 11:57:32 +03:30
parent 4dcc574e19
commit a6cf440840

View File

@@ -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 { class SDUIFormWidget extends StatelessWidget {
final SDUIWidgetModel model; final SDUIWidgetModel model;
final Map<String, TextEditingController>? controllers; final Map<String, TextEditingController>? controllers;
@@ -187,15 +282,25 @@ class SDUIFormWidget extends StatelessWidget {
if (visibleCondition.contains('activeStepperIndex == 0')) { if (visibleCondition.contains('activeStepperIndex == 0')) {
return builder(); return builder();
} }
return const SizedBox.shrink(); return Visibility(
visible: false,
maintainSize: false,
maintainState: false,
maintainAnimation: false,
child: builder(),
);
} }
// Use Obx for reactive updates // Use Obx for reactive updates
return Obx(() { return Obx(() {
if (!_evaluateVisibleCondition(visibleCondition)) { final isVisible = _evaluateVisibleCondition(visibleCondition);
return const SizedBox.shrink(); return Visibility(
} visible: isVisible,
return builder(); maintainSize: false,
maintainState: false,
maintainAnimation: false,
child: builder(),
);
}); });
} }
@@ -316,7 +421,6 @@ class SDUIFormWidget extends StatelessWidget {
double paddingVertical, double paddingVertical,
) { ) {
if (children.isEmpty) { if (children.isEmpty) {
iLog('Column has no children');
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
@@ -328,31 +432,84 @@ class SDUIFormWidget extends StatelessWidget {
crossAxisAlignment, 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 { 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) { } catch (e) {
iLog('Error building column child: $e'); iLog('Error building column child: $e');
return Container( visibleConditions.add(null);
builtChildren.add(
Container(
padding: EdgeInsets.all(8), padding: EdgeInsets.all(8),
color: Colors.yellow.withAlpha(10), color: Colors.yellow.withAlpha(10),
child: Text('Child Error'), child: Text('Child Error'),
),
); );
} }
}).toList(); }
// Add spacing between children // Add spacing between children
final columnChildren = spacing > 0 && builtChildren.length > 1 // Wrap each child (except first) with spacing that only shows if previous child is visible
? <Widget>[] final columnChildren = <Widget>[];
: builtChildren;
if (spacing > 0 && builtChildren.length > 1) {
for (int i = 0; i < builtChildren.length; i++) { for (int i = 0; i < builtChildren.length; i++) {
columnChildren.add(builtChildren[i]); final widget = builtChildren[i];
if (i < builtChildren.length - 1) {
columnChildren.add(SizedBox(height: spacing)); 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( final column = Column(
@@ -849,6 +1006,8 @@ class SDUIFormWidget extends StatelessWidget {
'sdui_form_stepper_${stepperInfo.stepperData.key ?? 'default'}'; 'sdui_form_stepper_${stepperInfo.stepperData.key ?? 'default'}';
SDUIFormWidgetController formController; SDUIFormWidgetController formController;
fLog('mj ==>build With Stepper Layout');
try { try {
formController = Get.find<SDUIFormWidgetController>(tag: controllerTag); formController = Get.find<SDUIFormWidgetController>(tag: controllerTag);
} catch (_) { } catch (_) {
@@ -931,6 +1090,7 @@ class SDUIFormWidget extends StatelessWidget {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: 30.h,
children: contentWidgets, children: contentWidgets,
), ),
), ),