Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import '../../../shared/analytics/analytics.dart' as ga;
import '../../../shared/analytics/constants.dart' as gac;
import '../../../shared/editor/api_classes.dart';
import '../../../shared/editor/editor_client.dart';
import '../../../shared/ui/search.dart';
import 'property_editor_types.dart';

typedef EditableWidgetData =
({List<EditableArgument> args, String? name, String? documentation});
typedef EditableWidgetData = ({String? name, String? documentation});

typedef EditArgumentFunction =
Future<EditArgumentResponse?> Function<T>({
Expand All @@ -20,23 +21,33 @@ typedef EditArgumentFunction =
});

class PropertyEditorController extends DisposableController
with AutoDisposeControllerMixin {
with AutoDisposeControllerMixin, SearchControllerMixin<EditableProperty> {
Comment thread
elliette marked this conversation as resolved.
Outdated
PropertyEditorController(this.editorClient) {
_init();
init();
}

final EditorClient editorClient;

String get gaId => gac.PropertyEditorSidebar.id;

TextDocument? _currentDocument;
CursorPosition? _currentCursorPosition;

ValueListenable<EditableWidgetData?> get editableWidgetData =>
_editableWidgetData;
final _editableWidgetData = ValueNotifier<EditableWidgetData?>(null);

void _init() {
bool get filterApplied => _filterApplied;
bool _filterApplied = false;

ValueListenable<List<EditableProperty>> get propertiesToDisplay =>
_propertiesToDisplay;
final _propertiesToDisplay = ValueNotifier<List<EditableProperty>>([]);

TextDocument? _currentDocument;
CursorPosition? _currentCursorPosition;
List<EditableProperty>? _editableProperties;

@override
void init() {
super.init();
autoDisposeStreamSubscription(
editorClient.activeLocationChangedStream.listen((event) async {
final textDocument = event.textDocument;
Expand All @@ -59,20 +70,30 @@ class PropertyEditorController extends DisposableController
);
final args = result?.args ?? <EditableArgument>[];
final name = result?.name;
_editableProperties = args.map(argToProperty).nonNulls.toList();
refreshSearchMatches();
_updateSearchResults();
_editableWidgetData.value = (
args: args,
name: name,
documentation: result?.documentation,
);

// Register impression.
ga.impression(
gaId,
gac.PropertyEditorSidebar.widgetPropertiesUpdate(name: name),
);
}),
);

addAutoDisposeListener(searchMatches, _updateSearchResults);
addAutoDisposeListener(searchNotifier, _updateSearchResults);
}

@override
Iterable<EditableProperty> get currentDataToSearchThrough =>
_editableProperties ?? <EditableProperty>[];

Future<EditArgumentResponse?> editArgument<T>({
required String name,
required T value,
Expand All @@ -88,15 +109,30 @@ class PropertyEditorController extends DisposableController
);
}

void _updateSearchResults() {
if (search.isEmpty) {
_clearSearch();
return;
}
_filterApplied = true;
_propertiesToDisplay.value = searchMatches.value;
}

void _clearSearch() {
_filterApplied = false;
_propertiesToDisplay.value = _editableProperties ?? [];
}

@visibleForTesting
void initForTestsOnly({
EditableArgumentsResult? editableArgsResult,
TextDocument? document,
CursorPosition? cursorPosition,
}) {
if (editableArgsResult != null) {
_editableProperties =
editableArgsResult.args.map(argToProperty).nonNulls.toList();
_editableWidgetData.value = (
args: editableArgsResult.args,
name: editableArgsResult.name,
documentation: editableArgsResult.documentation,
);
Expand All @@ -107,5 +143,7 @@ class PropertyEditorController extends DisposableController
if (cursorPosition != null) {
_currentCursorPosition = cursorPosition;
}
search = '';
_clearSearch();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import 'package:devtools_app_shared/utils.dart';
import 'package:meta/meta.dart';

import '../../../shared/editor/api_classes.dart';
import '../../../shared/primitives/utils.dart';
import '../../../shared/ui/search.dart';

/// Record representing an option for an [EditableProperty].
typedef PropertyOption = ({String text, bool isDefault});
Expand Down Expand Up @@ -130,7 +132,7 @@ class EditableEnum extends EditableProperty with FiniteValuesProperty {
}
}

class EditableProperty extends EditableArgument {
class EditableProperty extends EditableArgument with SearchableDataMixin {
Comment thread
elliette marked this conversation as resolved.
Outdated
EditableProperty(EditableArgument argument)
: super(
name: argument.name,
Expand Down Expand Up @@ -167,6 +169,13 @@ class EditableProperty extends EditableArgument {
Object? convertFromInputString(String? _) {
throw UnimplementedError();
}

@override
bool matchesSearchToken(RegExp regExpSearch) {
return name.caseInsensitiveContains(regExpSearch) ||
valueDisplay.caseInsensitiveContains(regExpSearch) ||
type.caseInsensitiveContains(regExpSearch);
}
}

mixin NumericProperty on EditableProperty {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:flutter/material.dart';

import '../../../shared/primitives/utils.dart';
import '../../../shared/ui/common_widgets.dart';
import '../../../shared/ui/search.dart';
import 'property_editor_controller.dart';
import 'property_editor_inputs.dart';
import 'property_editor_types.dart';
Expand All @@ -25,6 +26,7 @@ class PropertyEditorView extends StatelessWidget {
controller.editorClient.editArgumentMethodName,
controller.editorClient.editableArgumentsMethodName,
controller.editableWidgetData,
controller.propertiesToDisplay,
],
builder: (_, values, _) {
final editArgumentMethodName = values.first as String?;
Expand All @@ -42,7 +44,8 @@ class PropertyEditorView extends StatelessWidget {
);
}

final (:args, :name, :documentation) = editableWidgetData;
final properties = values.fourth as List<EditableProperty>;
final (:name, :documentation) = editableWidgetData;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expand All @@ -51,11 +54,11 @@ class PropertyEditorView extends StatelessWidget {
name: name,
documentation: documentation,
),
args.isEmpty
properties.isEmpty && !controller.filterApplied
? _NoEditablePropertiesMessage(name: name)
: _PropertiesList(
editableProperties: args.map(argToProperty).nonNulls.toList(),
editProperty: controller.editArgument,
controller: controller,
editableProperties: properties,
),
],
);
Expand All @@ -66,12 +69,12 @@ class PropertyEditorView extends StatelessWidget {

class _PropertiesList extends StatefulWidget {
const _PropertiesList({
required this.controller,
required this.editableProperties,
required this.editProperty,
});

final PropertyEditorController controller;
final List<EditableProperty> editableProperties;
final EditArgumentFunction editProperty;

static const defaultItemPadding = borderPadding;
static const denseItemPadding = defaultItemPadding / 2;
Expand Down Expand Up @@ -99,10 +102,13 @@ class _PropertiesListState extends State<_PropertiesList> {
Widget build(BuildContext context) {
return Column(
children: <Widget>[
_SearchControls(controller: widget.controller),
if (widget.editableProperties.isEmpty)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

what if editableProperties is empty and the filter query is empty? In this case, this message may not make sense

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That is actually handled before we get here - if there are no editable properties at all we display a message instead of rendering the _PropertiesList:

const _NoMatchingPropertiesMessage(),
for (final property in widget.editableProperties)
_EditablePropertyItem(
property: property,
editProperty: widget.editProperty,
editProperty: widget.controller.editArgument,
),
].joinWith(const PaddedDivider.noPadding()),
);
Expand Down Expand Up @@ -142,6 +148,32 @@ class _EditablePropertyItem extends StatelessWidget {
}
}

class _SearchControls extends StatelessWidget {
const _SearchControls({required this.controller});

final PropertyEditorController controller;

static const _searchFieldHeight = 32.0;

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(_PropertiesList.defaultItemPadding),
child: Row(
children: [
Expanded(
child: SearchField<PropertyEditorController>(
searchController: controller,
supportsNavigation: false,
searchFieldHeight: _searchFieldHeight,
),
),
],
),
);
}
}

class _PropertyLabels extends StatelessWidget {
const _PropertyLabels({required this.property});

Expand Down Expand Up @@ -289,6 +321,15 @@ class _NoEditablePropertiesMessage extends StatelessWidget {
}
}

class _NoMatchingPropertiesMessage extends StatelessWidget {
const _NoMatchingPropertiesMessage();

@override
Widget build(BuildContext context) {
return const Text('No properties matching the current filter.');
}
}

class _WidgetNameAndDocumentation extends StatelessWidget {
const _WidgetNameAndDocumentation({required this.name, this.documentation});

Expand Down Expand Up @@ -320,7 +361,7 @@ class _WidgetNameAndDocumentation extends StatelessWidget {
),
],
),
const PaddedDivider(),
const PaddedDivider(padding: EdgeInsets.all(noPadding)),
Comment thread
elliette marked this conversation as resolved.
Outdated
],
);
}
Expand Down
Loading