Skip to content

Conversation

@jslavitz
Copy link
Contributor

fixes #19240

/// The duration of the expansion animation.
final Duration animationDuration;

//Whether multiple panels can be open simultaneously
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: space between // and text

if (!widget._allowMultiplePanelsOpen) {
for (int i = 0; i < widget.children.length; i += 1) {
assert(widget.children[i] is ExpansionPanelRadio,
'All children of ExpansionPanel.radio need to be of type ExpansionPanelRadio');
Copy link
Contributor

Choose a reason for hiding this comment

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

indent with 2 spaces

}

assert(_debugCheckExpandLimit(),
'This expansion panel widget initialized with more than one panel open');
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

@override
void initState() {
super.initState();
if (!widget._allowMultiplePanelsOpen) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since you are always using the negation of this field, consider changing it to _preventMultiplePanelsOpen or something similar

}
_openPanels[pressedChild.value] = !isExpanded;
}
setState((){});
Copy link
Contributor

Choose a reason for hiding this comment

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

You only want to setState if you aren't allowing multiple panels


void _handlePressed(bool isExpanded, int index) {
if (widget.expansionCallback != null)
widget.expansionCallback(index, isExpanded);
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this callback get invoked twice in radio mode?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean by the rest of the code below? I don't think so, only possibly one other panel if it was open before.

context,
children[index].isExpanded,
widget._allowMultiplePanelsOpen ? widget.children[index].isExpanded :
_openPanels[_widgetChild.value],
Copy link
Contributor

Choose a reason for hiding this comment

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

Indent with 2 lines


testWidgets('Single Panel Open Test', (WidgetTester tester) async {

List<ExpansionPanel> _demoItems;
Copy link
Contributor

Choose a reason for hiding this comment

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

Initialize variables where they are declared

}) : assert(headerBuilder != null),
assert(body != null),
assert(isExpanded != null);
assert(body != null),
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: keep asserts lined up

bool panelExpanded = false;
for (int i = 0; i < widget.children.length; i += 1) {
assert(widget.children[i] is ExpansionPanelRadio,
'All children of ExpansionPanel.radio need to be of type ExpansionPanelRadio');
Copy link
Contributor

Choose a reason for hiding this comment

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

Indent by 2 spaces

final int childKey = child.value;
final bool panelWillBeExpanded = child.initializesExpanded || (childKey == _currentOpenPanel?.value);
assert(!panelExpanded && panelWillBeExpanded || panelExpanded && !panelWillBeExpanded,
'Trying to initialize radio panel list with more than two open panels!');
Copy link
Contributor

Choose a reason for hiding this comment

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

Indent by 2 spaces

void initState() {
super.initState();
if (widget._allowOnlyOnePanelOpen) {
for (int i = 0; i < widget.children.length; i += 1) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since you don't need the index i for anything, use for (ExpansionPanelRadio child in widget.children), here and elsewhere. I don't think you need to assert in initState unless you are dealing with the radio -> non radio or reverse

@override
void didUpdateWidget(ExpansionPanelList oldWidget) {
super.didUpdateWidget(oldWidget);

Copy link
Contributor

Choose a reason for hiding this comment

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

What happens if I change from radio to non-radio or likewise?

expect(tester.getRect(find.byType(AnimatedSize).at(2)), new Rect.fromLTWH(0.0, 56.0 + 1.0 + 56.0 + 16.0 + 16.0 + 48.0 + 16.0, 800.0, 100.0));
});

testWidgets('Single Panel Open Test', (WidgetTester tester) async {
Copy link
Contributor

Choose a reason for hiding this comment

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

Make sure you test adding/removing panels in radio mode (especially the open panel), and switch from radio to non radio

}) : assert(headerBuilder != null),
assert(body != null),
assert(isExpanded != null);
}) : assert(headerBuilder != null),
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove the extra spaces, here and below in the initializer list.


/// An expansion panel that allows for radio-like functionality.
///
/// This type of panel will automatically handle closing and opening itself,
Copy link
Contributor

Choose a reason for hiding this comment

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

Try and keep these doc comments to 80 columns

/// An expansion panel that allows for radio-like functionality.
///
/// This type of panel will automatically handle closing and opening itself,
/// set the [initializesExpanded] value to true on a panel if you want it to begin
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure about placing initializesExpanded on the RadioPanel. Try adding another named argument to the ExpansionPanelList.radio constructor which takes a panel or value of a panel to open "only the first time it is created". Then don't both updating in the future, it doesn't make sense to try and keep all of the initializesExpanded and state changed by user interaction in sync.

@required this.value,
@required ExpansionPanelHeaderBuilder headerBuilder,
@required Widget body,
}) : assert(initializesExpanded != null),
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above, 1 space here.

/// Whether this panel initializes expanded or not.
final bool initializesExpanded;

/// Identifier that corresponds to this specific object.
Copy link
Contributor

Choose a reason for hiding this comment

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

"The value that uniquely identifies a radio panel"

Copy link
Contributor

Choose a reason for hiding this comment

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

Also this should be Object like I said, otherwise I can't use a String key

_currentOpenPanel = child;
}
}
else if(oldWidget._allowOnlyOnePanelOpen) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Move this to the previous line so that it directly follows the previous closing }.

}
else if(oldWidget._allowOnlyOnePanelOpen) {
_currentOpenPanel = null;
setState((){});
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't/shouldn't setState in didUpdateWidget, because your state is already dirty. Might have been a miscommunication - this is only required in _handlePressed

if (_isChildExpanded(index) && index != 0 && !_isChildExpanded(index - 1))
items.add(new MaterialGap(key: new _SaltedKey<BuildContext, int>(context, index * 2 - 1)));

final ExpansionPanelRadio _widgetChild = widget._allowOnlyOnePanelOpen ? widget.children[index] : null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't make locals private, rename to "radioPanel"

child: widget.children[index].headerBuilder(
context,
children[index].isExpanded,
widget._allowOnlyOnePanelOpen ? _widgetChild.value == _currentOpenPanel?.value:
Copy link
Contributor

Choose a reason for hiding this comment

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

use the _isChildExpanded callback

/// [ExpansionPanelRadio].
const ExpansionPanelList.radio({
Key key,
this.children = const <ExpansionPanelRadio>[],
Copy link
Contributor

Choose a reason for hiding this comment

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

Something I missed earlier - this isn't a type annotation for children, it is just the type for the default value. You need to use an explicitly typed param with an initializer.

({
  List<ExpansionPanelRadio> children = ..,
}) : children = children,

/// A unique identifier [value] must be assigned to each panel.
class ExpansionPanelRadio extends ExpansionPanel {

/// A subclass of expansion panel that allows for radio functionality.
Copy link
Contributor

Choose a reason for hiding this comment

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

Just say "An expansion panel" like you had above. Don't put the "subclass of" part in because if that changes, it's easy for the docs to get missed and be out of date.


/// A subclass of expansion panel that allows for radio functionality.
///
/// A unique identifier [value] must be passed into the constructor. The
Copy link
Contributor

Choose a reason for hiding this comment

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

Take out the word "identifier": it reads better as "A unique [value]".

Also, explain why it must be unique: say something like "The [value] is used to indicate which panel is currently selected."

}) : assert(value != null),
super(body: body, headerBuilder: headerBuilder);

/// The value that uniquely identifies a radio panel.
Copy link
Contributor

Choose a reason for hiding this comment

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

Add why it exists: "so that the currently selected radio panel may be identified."

final bool _allowOnlyOnePanelOpen;

/// The value of the panel that initially begins open. (This value is
/// only used when initializing with the radio constructor.)
Copy link
Contributor

Choose a reason for hiding this comment

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

radio -> [ExpansionPanelList.radio]

child: new ConstrainedBox(
constraints: const BoxConstraints(minHeight: _kPanelHeaderCollapsedHeight),
child: children[index].headerBuilder(
child: widget.children[index].headerBuilder(
Copy link
Contributor

Choose a reason for hiding this comment

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

Since it's used more than once, you can add:

final ExpansionPanelRadio child = widget.children[index];

above, and use child.headerBuilder( here, and below.

/// This widget allows for at most one panel in the list to be open.
/// The expansion panel callback is triggered when an expansion panel
/// expand/collapse button is pushed. The [children] and [animationDuration]
/// arguments must not be null. The [children] objects also must of type
Copy link
Contributor

Choose a reason for hiding this comment

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

"objects also must of type" --> "objects must be instances of"

@gspencergoog
Copy link
Contributor

32384589-a60f0e74-c078-11e7-9bc1-e5b5287aea9d

@jslavitz jslavitz added cla: yes and removed cla: no labels Jul 25, 2018
@flutter flutter deleted a comment from googlebot Jul 25, 2018
@flutter flutter deleted a comment from googlebot Jul 25, 2018
@jslavitz jslavitz merged commit 28dc007 into flutter:master Jul 25, 2018
@jslavitz jslavitz deleted the expansionPanel3 branch December 3, 2018 22:29
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add single expanded ExpasionPanel in an ExpansionPanelList option

4 participants