Skip to content

Conversation

@divyanshub024
Copy link
Member

@divyanshub024 divyanshub024 commented Nov 4, 2025

Description

  • Refactored StacRadioParser and StacRadioGroupParser to remove unnecessary dependencies and streamline widget structure.
  • Converted StacRadioWidget to a StatefulWidget for better state management.
  • Removed StacRadioGroupScope in favor of direct state management within StacRadioGroup.
  • Added new properties to StacRadio for enhanced customization: enabled, backgroundColor, side, and innerRadius.

Type of Change

  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Code refactor
  • Build configuration change
  • Documentation
  • Chore

Summary by CodeRabbit

  • New Features

    • Radios gain new customization: enabled state, background color, border side, and inner-radius control.
    • Radio groups support an onChanged callback to react to value changes.
  • Refactor

    • Internal radio and radio-group implementations reworked to improve focus, state lifecycle, and form synchronization.
  • Documentation

    • Radio properties docs updated to include the new customization options.

- Refactored StacRadioParser and StacRadioGroupParser to remove unnecessary dependencies and streamline widget structure.
- Converted StacRadioWidget to a StatefulWidget for better state management.
- Removed StacRadioGroupScope in favor of direct state management within StacRadioGroup.
- Added new properties to StacRadio for enhanced customization: enabled, backgroundColor, side, and innerRadius.
- Updated JSON serialization for new properties in StacRadio and StacRadioGroup.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

Walkthrough

Converted radio widgets to internal stateful management: removed the InheritedWidget radio scope, introduced a FocusNode-owning _RadioWidgetState, replaced ValueNotifier group state with a private _groupValue, and extended core models (StacRadio, StacRadioGroup) with new visual and callback fields.

Changes

Cohort / File(s) Summary
Radio widget parser refactor
packages/stac/lib/src/parsers/widgets/stac_radio/stac_radio_parser.dart
_RadioWidget changed from StatelessWidget to StatefulWidget; added _RadioWidgetState with a private FocusNode (init/dispose). Builders now read widget.model and use the state's _focusNode; removed dependency on radioGroupScope and ValueListenable wrappers.
Radio group parser refactor
packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_parser.dart
Replaced ValueNotifier with private dynamic _groupValue; constructor changed to positional; added didUpdateWidget; introduced _onChanged to update _groupValue, persist formData when id exists, and call model.onChanged. Builds RadioGroup<dynamic> directly.
Removed radio group scope
packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_scope.dart
Deleted StacRadioGroupScope InheritedWidget and its of() accessor, removing the prior scope-based API.
StacRadio model extension
packages/stac_core/lib/widgets/radio/stac_radio.dart, packages/stac_core/lib/widgets/radio/stac_radio.g.dart
Added fields to StacRadio: enabled (bool?), backgroundColor (StacColor?), side (StacBorderSide?), innerRadius (double? with @DoubleConverter); updated constructor and generated (de)serialization.
StacRadioGroup model extension
packages/stac_core/lib/widgets/radio_group/stac_radio_group.dart, packages/stac_core/lib/widgets/radio_group/stac_radio_group.g.dart
Added onChanged (StacAction?) to StacRadioGroup; updated constructor and generated (de)serialization to read/write onChanged.
Docs update
docs/widgets/radio_group.mdx
Documented new StacRadio properties: enabled, backgroundColor, side, innerRadius in the radio properties table.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Parser as RadioGroupParser
    participant Group as RadioGroup
    participant RadioState as _RadioWidgetState
    participant Model as StacRadio / StacRadioGroup

    Parser->>RadioState: initialize _groupValue from model (initState)
    RadioState->>RadioState: create FocusNode
    Parser->>Group: build RadioGroup(groupValue: _groupValue, onChanged: _onChanged)
    Group->>RadioState: user selects option -> onChanged(value)
    RadioState->>RadioState: _onChanged updates _groupValue, writes formData if id
    RadioState->>Model: invoke model.onChanged (if present)
    RadioState->>RadioState: setState -> rebuild radios using widget.model and _focusNode
    RadioState->>RadioState: dispose() -> dispose FocusNode
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to:
    • FocusNode lifecycle and usages in _RadioWidgetState.
    • Correct propagation in _onChanged (state, formData, model.onChanged).
    • Removal of StacRadioGroupScope: search for residual uses.
    • JSON (de)serialization changes for nested/new fields (StacBorderSide, StacAction, DoubleConverter).

Possibly related PRs

Suggested reviewers

  • Potatomonsta

Poem

🐰 I tended the radios, gave focus a home,
The scope hopped away, now state calls the roam.
Borders and colors and inner-whim play,
Group whispers changes — I nibble and sway.
A little rabbit applauds this new way. 🥕✨

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately reflects the main changes: refactoring and simplification of StacRadio and StacRadioGroup by removing unnecessary dependencies (StacRadioGroupScope), converting widgets to StatefulWidget, and streamlining state management.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dv/radio-fix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9664784 and bb75623.

📒 Files selected for processing (7)
  • packages/stac/lib/src/parsers/widgets/stac_radio/stac_radio_parser.dart (2 hunks)
  • packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_parser.dart (2 hunks)
  • packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_scope.dart (0 hunks)
  • packages/stac_core/lib/widgets/radio/stac_radio.dart (2 hunks)
  • packages/stac_core/lib/widgets/radio/stac_radio.g.dart (2 hunks)
  • packages/stac_core/lib/widgets/radio_group/stac_radio_group.dart (3 hunks)
  • packages/stac_core/lib/widgets/radio_group/stac_radio_group.g.dart (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_scope.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: pub_get_check
  • GitHub Check: analyze
  • GitHub Check: format

Comment on lines +62 to 141
Widget _buildCupertinoRadio(BuildContext context) {
return CupertinoRadio<dynamic>(
value: widget.model.value,
mouseCursor: widget.model.mouseCursor?.parse,
toggleable: widget.model.toggleable ?? false,
activeColor: widget.model.activeColor?.toColor(context),
inactiveColor: widget.model.inactiveColor?.toColor(context),
fillColor: widget.model.fillColor?.toColor(context),
focusColor: widget.model.focusColor?.toColor(context),
focusNode: _focusNode,
autofocus: widget.model.autofocus ?? false,
useCheckmarkStyle: widget.model.useCheckmarkStyle ?? false,
enabled: widget.model.enabled,
);
}

Widget _buildAdaptiveRadio(
BuildContext context,
StacRadio model,
FocusNode focusNode,
) {
return ValueListenableBuilder(
valueListenable: radioGroupScope!.radioGroupValue,
builder: (context, value, child) {
return Radio.adaptive(
value: model.value,
mouseCursor: model.mouseCursor?.parse,
toggleable: model.toggleable ?? false,
activeColor: model.activeColor?.toColor(context),
fillColor: WidgetStateProperty.all(model.fillColor?.toColor(context)),
focusColor: model.focusColor?.toColor(context),
hoverColor: model.hoverColor?.toColor(context),
overlayColor: WidgetStateProperty.all(
model.overlayColor?.toColor(context),
),
splashRadius: model.splashRadius,
materialTapTargetSize: model.materialTapTargetSize?.parse,
visualDensity: model.visualDensity?.parse,
focusNode: focusNode,
autofocus: model.autofocus ?? false,
useCupertinoCheckmarkStyle: model.useCupertinoCheckmarkStyle ?? false,
);
},
Widget _buildAdaptiveRadio(BuildContext context) {
return Radio<dynamic>.adaptive(
value: widget.model.value,
mouseCursor: widget.model.mouseCursor?.parse,
toggleable: widget.model.toggleable ?? false,
activeColor: widget.model.activeColor?.toColor(context),
fillColor: WidgetStateProperty.all(
widget.model.fillColor?.toColor(context),
),
focusColor: widget.model.focusColor?.toColor(context),
hoverColor: widget.model.hoverColor?.toColor(context),
overlayColor: WidgetStateProperty.all(
widget.model.overlayColor?.toColor(context),
),
splashRadius: widget.model.splashRadius,
materialTapTargetSize: widget.model.materialTapTargetSize?.parse,
visualDensity: widget.model.visualDensity?.parse,
focusNode: _focusNode,
autofocus: widget.model.autofocus ?? false,
useCupertinoCheckmarkStyle:
widget.model.useCupertinoCheckmarkStyle ?? false,
enabled: widget.model.enabled,
backgroundColor: widget.model.backgroundColor != null
? WidgetStateProperty.all(
widget.model.backgroundColor!.toColor(context),
)
: null,
side: widget.model.side?.parse(context),
innerRadius: widget.model.innerRadius != null
? WidgetStateProperty.all(widget.model.innerRadius)
: null,
);
}

Widget _buildMaterialRadio(
BuildContext context,
StacRadio model,
FocusNode focusNode,
) {
return ValueListenableBuilder(
valueListenable: radioGroupScope!.radioGroupValue,
builder: (context, value, child) {
return Radio(
value: model.value,
mouseCursor: model.mouseCursor?.parse,
toggleable: model.toggleable ?? false,
activeColor: model.activeColor?.toColor(context),
fillColor: WidgetStateProperty.all(model.fillColor?.toColor(context)),
focusColor: model.focusColor?.toColor(context),
hoverColor: model.hoverColor?.toColor(context),
overlayColor: WidgetStateProperty.all(
model.overlayColor?.toColor(context),
),
splashRadius: model.splashRadius,
materialTapTargetSize: model.materialTapTargetSize?.parse,
visualDensity: model.visualDensity?.parse,
focusNode: focusNode,
autofocus: model.autofocus ?? false,
);
},
Widget _buildMaterialRadio(BuildContext context) {
return Radio<dynamic>(
value: widget.model.value,
mouseCursor: widget.model.mouseCursor?.parse,
toggleable: widget.model.toggleable ?? false,
activeColor: widget.model.activeColor?.toColor(context),
fillColor: WidgetStateProperty.all(
widget.model.fillColor?.toColor(context),
),
focusColor: widget.model.focusColor?.toColor(context),
hoverColor: widget.model.hoverColor?.toColor(context),
overlayColor: WidgetStateProperty.all(
widget.model.overlayColor?.toColor(context),
),
splashRadius: widget.model.splashRadius,
materialTapTargetSize: widget.model.materialTapTargetSize?.parse,
visualDensity: widget.model.visualDensity?.parse,
focusNode: _focusNode,
autofocus: widget.model.autofocus ?? false,
enabled: widget.model.enabled,
backgroundColor: widget.model.backgroundColor != null
? WidgetStateProperty.all(
widget.model.backgroundColor!.toColor(context),
)
: null,
side: widget.model.side?.parse(context),
innerRadius: widget.model.innerRadius != null
? WidgetStateProperty.all(widget.model.innerRadius)
: null,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Pass the group wiring to every Radio.

CupertinoRadio, Radio.adaptive, and Radio all require groupValue and onChanged. After removing StacRadioGroupScope, these calls no longer compile and, even if they did, taps couldn’t update the group. Please fetch the current group wiring from the new RadioGroup wrapper and feed it into each constructor.

Apply this diff to restore the required wiring:

   @override
   Widget build(BuildContext context) {
-    switch (widget.model.radioType ?? StacRadioType.material) {
+    final radioGroup = RadioGroup.of<dynamic>(context);
+    switch (widget.model.radioType ?? StacRadioType.material) {
       case StacRadioType.cupertino:
-        return _buildCupertinoRadio(context);
+        return _buildCupertinoRadio(context, radioGroup?.groupValue,
+            radioGroup?.onChanged ?? (_) {});
       case StacRadioType.adaptive:
-        return _buildAdaptiveRadio(context);
+        return _buildAdaptiveRadio(context, radioGroup?.groupValue,
+            radioGroup?.onChanged ?? (_) {});
       case StacRadioType.material:
-        return _buildMaterialRadio(context);
+        return _buildMaterialRadio(context, radioGroup?.groupValue,
+            radioGroup?.onChanged ?? (_) {});
     }
   }

-  Widget _buildCupertinoRadio(BuildContext context) {
+  Widget _buildCupertinoRadio(
+    BuildContext context,
+    dynamic groupValue,
+    ValueChanged<dynamic> onChanged,
+  ) {
     return CupertinoRadio<dynamic>(
       value: widget.model.value,
+      groupValue: groupValue,
+      onChanged: onChanged,
       mouseCursor: widget.model.mouseCursor?.parse,
       toggleable: widget.model.toggleable ?? false,
       activeColor: widget.model.activeColor?.toColor(context),
       inactiveColor: widget.model.inactiveColor?.toColor(context),
       fillColor: widget.model.fillColor?.toColor(context),
       focusColor: widget.model.focusColor?.toColor(context),
       focusNode: _focusNode,
       autofocus: widget.model.autofocus ?? false,
       useCheckmarkStyle: widget.model.useCheckmarkStyle ?? false,
       enabled: widget.model.enabled,
     );
   }

-  Widget _buildAdaptiveRadio(BuildContext context) {
+  Widget _buildAdaptiveRadio(
+    BuildContext context,
+    dynamic groupValue,
+    ValueChanged<dynamic> onChanged,
+  ) {
     return Radio<dynamic>.adaptive(
       value: widget.model.value,
+      groupValue: groupValue,
+      onChanged: onChanged,
       mouseCursor: widget.model.mouseCursor?.parse,
       toggleable: widget.model.toggleable ?? false,
       activeColor: widget.model.activeColor?.toColor(context),
       fillColor: WidgetStateProperty.all(
         widget.model.fillColor?.toColor(context),
       ),
       focusColor: widget.model.focusColor?.toColor(context),
       hoverColor: widget.model.hoverColor?.toColor(context),
       overlayColor: WidgetStateProperty.all(
         widget.model.overlayColor?.toColor(context),
       ),
       splashRadius: widget.model.splashRadius,
       materialTapTargetSize: widget.model.materialTapTargetSize?.parse,
       visualDensity: widget.model.visualDensity?.parse,
       focusNode: _focusNode,
       autofocus: widget.model.autofocus ?? false,
       useCupertinoCheckmarkStyle:
           widget.model.useCupertinoCheckmarkStyle ?? false,
       enabled: widget.model.enabled,
       backgroundColor: widget.model.backgroundColor != null
           ? WidgetStateProperty.all(
               widget.model.backgroundColor!.toColor(context),
             )
           : null,
       side: widget.model.side?.parse(context),
       innerRadius: widget.model.innerRadius != null
           ? WidgetStateProperty.all(widget.model.innerRadius)
           : null,
     );
   }

-  Widget _buildMaterialRadio(BuildContext context) {
+  Widget _buildMaterialRadio(
+    BuildContext context,
+    dynamic groupValue,
+    ValueChanged<dynamic> onChanged,
+  ) {
     return Radio<dynamic>(
       value: widget.model.value,
+      groupValue: groupValue,
+      onChanged: onChanged,
       mouseCursor: widget.model.mouseCursor?.parse,
       toggleable: widget.model.toggleable ?? false,
       activeColor: widget.model.activeColor?.toColor(context),
       fillColor: WidgetStateProperty.all(
         widget.model.fillColor?.toColor(context),
       ),
       focusColor: widget.model.focusColor?.toColor(context),
       hoverColor: widget.model.hoverColor?.toColor(context),
       overlayColor: WidgetStateProperty.all(
         widget.model.overlayColor?.toColor(context),
       ),
       splashRadius: widget.model.splashRadius,
       materialTapTargetSize: widget.model.materialTapTargetSize?.parse,
       visualDensity: widget.model.visualDensity?.parse,
       focusNode: _focusNode,
       autofocus: widget.model.autofocus ?? false,
       enabled: widget.model.enabled,
       backgroundColor: widget.model.backgroundColor != null
           ? WidgetStateProperty.all(
               widget.model.backgroundColor!.toColor(context),
             )
           : null,
       side: widget.model.side?.parse(context),
       innerRadius: widget.model.innerRadius != null
           ? WidgetStateProperty.all(widget.model.innerRadius)
           : null,
     );
   }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/stac/lib/src/parsers/widgets/stac_radio/stac_radio_parser.dart
around lines 62 to 141, each Radio constructor is missing the required group
wiring (groupValue and onChanged) after removal of StacRadioGroupScope; fetch
the current group wiring from the new RadioGroup wrapper via
RadioGroup.of(context) and pass its groupValue and onChanged into
CupertinoRadio, Radio.adaptive, and Radio constructors (handle null safely so
existing enabled/toggleable behavior remains intact); ensure the RadioGroup
import is present and remove any stale StacRadioGroupScope references.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_parser.dart (2)

61-75: LGTM! Change handler is correct.

The method properly updates state with setState() and synchronizes form data. The form data synchronization logic is repeated in initState, didUpdateWidget, and here—consider extracting it to a helper method like _syncFormData(dynamic value) to reduce duplication.


77-84: LGTM! Build method is correct.

The widget correctly renders RadioGroup<dynamic> with local state and change handler. Using dynamic provides flexibility but reduces type safety—if radio values in a group share a specific type (e.g., String, int), consider parameterizing RadioGroup and _groupValue with that type to catch type errors at compile time.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb75623 and 9ed168a.

📒 Files selected for processing (2)
  • docs/widgets/radio_group.mdx (1 hunks)
  • packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_parser.dart (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/widgets/radio_group.mdx
🔇 Additional comments (4)
packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_parser.dart (4)

1-6: LGTM! Imports are appropriate.

The imports cover all necessary dependencies for the refactored radio group implementation.


8-22: LGTM! Parser implementation is clean.

The refactored parser correctly instantiates the private widget with positional parameters and properly retrieves the form scope.


24-32: LGTM! Widget structure is appropriate.

The StatefulWidget is properly defined with a clean positional constructor.


34-46: LGTM! Initialization logic is correct.

The state properly initializes _groupValue and synchronizes with form data when an ID is provided.

Comment on lines 48 to 59
@override
void dispose() {
groupValue.dispose();
super.dispose();
}
void didUpdateWidget(covariant _RadioGroupWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.model.groupValue != widget.model.groupValue) {
_groupValue = widget.model.groupValue;

void _updateGroupValue(dynamic value) {
groupValue.value = value;
_saveValueInFormData();
// Save to form data if id is provided
if (widget.model.id != null && widget.formScope != null) {
widget.formScope!.formData[widget.model.id!] = widget.model.groupValue;
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Wrap _groupValue assignment in setState().

Line 52 updates _groupValue without calling setState(), so the widget won't rebuild when groupValue changes externally (e.g., during form reset). This causes the UI to display a stale selection.

Apply this diff to trigger a rebuild:

   void didUpdateWidget(covariant _RadioGroupWidget oldWidget) {
     super.didUpdateWidget(oldWidget);
     if (oldWidget.model.groupValue != widget.model.groupValue) {
-      _groupValue = widget.model.groupValue;
+      setState(() {
+        _groupValue = widget.model.groupValue;
+      });
 
       // Save to form data if id is provided
       if (widget.model.id != null && widget.formScope != null) {
         widget.formScope!.formData[widget.model.id!] = widget.model.groupValue;
       }
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@override
void dispose() {
groupValue.dispose();
super.dispose();
}
void didUpdateWidget(covariant _RadioGroupWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.model.groupValue != widget.model.groupValue) {
_groupValue = widget.model.groupValue;
void _updateGroupValue(dynamic value) {
groupValue.value = value;
_saveValueInFormData();
// Save to form data if id is provided
if (widget.model.id != null && widget.formScope != null) {
widget.formScope!.formData[widget.model.id!] = widget.model.groupValue;
}
}
}
@override
void didUpdateWidget(covariant _RadioGroupWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.model.groupValue != widget.model.groupValue) {
setState(() {
_groupValue = widget.model.groupValue;
});
// Save to form data if id is provided
if (widget.model.id != null && widget.formScope != null) {
widget.formScope!.formData[widget.model.id!] = widget.model.groupValue;
}
}
}
🤖 Prompt for AI Agents
In
packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_parser.dart
around lines 48 to 59, _groupValue is updated directly in didUpdateWidget which
prevents the widget from rebuilding when groupValue changes externally; wrap the
assignment (and related stateful updates such as saving to formScope.formData)
inside setState(() { ... }) so the framework schedules a rebuild and the UI
reflects the new selection. Ensure setState only encloses mutable state changes
and leave the super.didUpdateWidget call unchanged.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_parser.dart (1)

50-61: Critical: Wrap _groupValue assignment in setState().

Line 54 updates _groupValue without calling setState(), so the widget won't rebuild when groupValue changes externally (e.g., during form reset). This causes the UI to display stale selections.

Apply this diff to trigger a rebuild:

   @override
   void didUpdateWidget(covariant _RadioGroupWidget oldWidget) {
     super.didUpdateWidget(oldWidget);
     if (oldWidget.model.groupValue != widget.model.groupValue) {
-      _groupValue = widget.model.groupValue;
+      setState(() {
+        _groupValue = widget.model.groupValue;
+      });

       // Save to form data if id is provided
       if (widget.model.id != null && widget.formScope != null) {
         widget.formScope!.formData[widget.model.id!] = widget.model.groupValue;
       }
     }
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ed168a and 90201d4.

📒 Files selected for processing (1)
  • packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_parser.dart (2 hunks)
🔇 Additional comments (4)
packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_parser.dart (4)

1-22: LGTM: Parser and imports are correctly structured.

The simplified positional constructor call and import changes align with the refactoring goals.


24-31: LGTM: Widget class correctly defined.

The simplified positional constructor and state class naming are appropriate for an internal widget.


63-77: LGTM: Change handler correctly implemented.

The _onChanged method properly uses setState() for the value update and correctly handles form data synchronization and action callbacks.


79-86: LGTM: Build method correctly constructs RadioGroup.

The widget correctly wires up _groupValue and _onChanged to the RadioGroup, and handles the child rendering appropriately.

Comment on lines 37 to 48
@override
void initState() {
super.initState();
groupValue = ValueNotifier<dynamic>(widget.model.groupValue);
_saveValueInFormData();
setState(() {
_groupValue = widget.model.groupValue;
});

// Initialize form data if id is provided
if (widget.model.id != null && widget.formScope != null) {
widget.formScope!.formData[widget.model.id!] = widget.model.groupValue;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Remove setState() from initState().

Calling setState() in initState() is incorrect because the widget hasn't been built yet. The framework will automatically schedule a build after initState() completes, so wrapping the assignment in setState() is unnecessary and violates Flutter's lifecycle contract.

Apply this diff to fix the issue:

   @override
   void initState() {
     super.initState();
-    setState(() {
-      _groupValue = widget.model.groupValue;
-    });
+    _groupValue = widget.model.groupValue;

     // Initialize form data if id is provided
     if (widget.model.id != null && widget.formScope != null) {
       widget.formScope!.formData[widget.model.id!] = widget.model.groupValue;
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@override
void initState() {
super.initState();
groupValue = ValueNotifier<dynamic>(widget.model.groupValue);
_saveValueInFormData();
setState(() {
_groupValue = widget.model.groupValue;
});
// Initialize form data if id is provided
if (widget.model.id != null && widget.formScope != null) {
widget.formScope!.formData[widget.model.id!] = widget.model.groupValue;
}
}
@override
void initState() {
super.initState();
_groupValue = widget.model.groupValue;
// Initialize form data if id is provided
if (widget.model.id != null && widget.formScope != null) {
widget.formScope!.formData[widget.model.id!] = widget.model.groupValue;
}
}
🤖 Prompt for AI Agents
In
packages/stac/lib/src/parsers/widgets/stac_radio_group/stac_radio_group_parser.dart
around lines 37 to 48, remove the call to setState() inside initState():
directly assign _groupValue = widget.model.groupValue without wrapping it in
setState, leaving the subsequent formScope initialization unchanged (i.e., keep
checking widget.model.id and widget.formScope and assigning
widget.formScope!.formData[widget.model.id!] = widget.model.groupValue).

@divyanshub024 divyanshub024 merged commit bb5af9a into dev Nov 7, 2025
6 checks passed
@divyanshub024 divyanshub024 deleted the dv/radio-fix branch November 7, 2025 14:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants