Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Object Inspector selector to use a drop down instead of a tab bar #6008

Merged
merged 3 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../../../shared/analytics/constants.dart' as gac;
import '../../../shared/common_widgets.dart';
import '../../../shared/split.dart';
import '../../../shared/ui/tab.dart';
import '../../../shared/ui/drop_down_button.dart';
import '../../debugger/program_explorer.dart';
import '../../debugger/program_explorer_model.dart';
import '../vm_developer_tools_controller.dart';
Expand Down Expand Up @@ -61,48 +62,120 @@ class _ObjectInspectorViewState extends State<_ObjectInspectorView>
axis: Axis.horizontal,
initialFractions: const [0.2, 0.8],
children: [
AnalyticsTabbedView(
const ObjectInspectorSelector(),
ObjectViewport(
controller: controller,
),
],
);
}
}

class ObjectInspectorSelector extends StatefulWidget {
const ObjectInspectorSelector({
super.key,
});

static const kProgramExplorer = 'Program Explorer';
static const kObjectStore = 'Object Store';
static const kClassHierarchy = 'Class Hierarchy';

@override
State<ObjectInspectorSelector> createState() =>
_ObjectInspectorSelectorState();
}

class _ObjectInspectorSelectorState extends State<ObjectInspectorSelector> {
String value = ObjectInspectorSelector.kProgramExplorer;
late ObjectInspectorViewController controller;

@override
void didChangeDependencies() {
super.didChangeDependencies();
final vmDeveloperToolsController =
Provider.of<VMDeveloperToolsController>(context);
controller = vmDeveloperToolsController.objectInspectorViewController;
unawaited(controller.init());
}

@override
Widget build(BuildContext context) {
return Column(
children: [
AnalyticsDropDownButton<String>(
gaScreen: gac.objectInspectorScreen,
tabs: [
(
tab: DevToolsTab.create(
tabName: 'Program Explorer',
gaPrefix: gac.programExplorer,
),
tabView: ProgramExplorer(
controller: controller.programExplorerController,
onNodeSelected: _onNodeSelected,
displayHeader: false,
),
gaDropDownId: gac.objectInspectorDropDown,
message: '',
isExpanded: true,
value: value,
roundedCornerOptions: const RoundedCornerOptions(
showBottomLeft: false,
showBottomRight: false,
),
items: [
_buildMenuItem(
ObjectInspectorSelector.kProgramExplorer,
gac.programExplorer,
),
(
tab: DevToolsTab.create(
tabName: 'Object Store',
gaPrefix: gac.objectStore,
),
tabView: ObjectStoreViewer(
controller: controller.objectStoreController,
onLinkTapped: controller.findAndSelectNodeForObject,
),
_buildMenuItem(
ObjectInspectorSelector.kObjectStore,
gac.objectStore,
),
(
tab: DevToolsTab.create(
tabName: 'Class Hierarchy',
gaPrefix: gac.classHierarchy,
),
tabView: ClassHierarchyExplorer(
controller: controller,
),
_buildMenuItem(
ObjectInspectorSelector.kClassHierarchy,
gac.classHierarchy,
),
],
onChanged: (newValue) => setState(() {
value = newValue!;
}),
),
ObjectViewport(
controller: controller,
Expanded(
child: RoundedOutlinedBorder(
showTopLeft: false,
showTopRight: false,
child: _selectedWidget(),
),
),
],
);
}

({DropdownMenuItem<String> item, String gaId}) _buildMenuItem(
String text,
String gaId,
) {
return (
item: DropdownMenuItem<String>(
value: text,
child: Text(text),
),
gaId: gaId,
);
}

Widget _selectedWidget() {
switch (value) {
case ObjectInspectorSelector.kProgramExplorer:
return ProgramExplorer(
controller: controller.programExplorerController,
onNodeSelected: _onNodeSelected,
displayHeader: false,
);
case ObjectInspectorSelector.kObjectStore:
return ObjectStoreViewer(
controller: controller.objectStoreController,
onLinkTapped: controller.findAndSelectNodeForObject,
);
case ObjectInspectorSelector.kClassHierarchy:
return ClassHierarchyExplorer(
controller: controller,
);
default:
throw StateError('Unexpected value: $value');
}
}

void _onNodeSelected(VMServiceObjectNode node) {
final objRef = node.object;
final location = node.location;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ const copyLogs = 'copyLogs';

// Object explorer:
const objectInspectorScreen = 'objectInspector';
const objectInspectorDropDown = 'dropdown';
const programExplorer = 'programExplorer';
const objectStore = 'objectStore';
const classHierarchy = 'classHierarchy';
Expand Down
49 changes: 44 additions & 5 deletions packages/devtools_app/lib/src/shared/common_widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1104,15 +1104,31 @@ class FilterButton extends StatelessWidget {
}
}

class RoundedCornerOptions {
const RoundedCornerOptions({
this.showTopLeft = true,
this.showTopRight = true,
this.showBottomLeft = true,
this.showBottomRight = true,
});

final bool showTopLeft;
final bool showTopRight;
final bool showBottomLeft;
final bool showBottomRight;
}

class RoundedDropDownButton<T> extends StatelessWidget {
const RoundedDropDownButton({
Key? key,
this.value,
this.onChanged,
this.isDense = false,
this.isExpanded = false,
this.style,
this.selectedItemBuilder,
this.items,
this.roundedCornerOptions,
}) : super(key: key);

final T? value;
Expand All @@ -1121,29 +1137,52 @@ class RoundedDropDownButton<T> extends StatelessWidget {

final bool isDense;

final bool isExpanded;

final TextStyle? style;

final DropdownButtonBuilder? selectedItemBuilder;

final List<DropdownMenuItem<T>>? items;

final RoundedCornerOptions? roundedCornerOptions;

@override
Widget build(BuildContext context) {
final bgColor = Theme.of(context).colorScheme.backgroundColorSelected;

Radius selectRadius(bool show) {
return show ? const Radius.circular(defaultBorderRadius) : Radius.zero;
}

final showTopLeft = roundedCornerOptions?.showTopLeft ?? true;
final showTopRight = roundedCornerOptions?.showTopRight ?? true;
final showBottomLeft = roundedCornerOptions?.showBottomLeft ?? true;
final showBottomRight = roundedCornerOptions?.showBottomRight ?? true;
return RoundedOutlinedBorder(
showTopLeft: showTopLeft,
showTopRight: showTopRight,
showBottomLeft: showBottomLeft,
showBottomRight: showBottomRight,
child: Center(
child: Container(
padding: const EdgeInsets.only(
left: defaultSpacing,
right: borderPadding,
),
child: SizedBox(
height: defaultButtonHeight - 2.0, // subtract 2.0 for width of border
child: DropdownButtonHideUnderline(
child: DropdownButton<T>(
padding: const EdgeInsets.only(
left: defaultSpacing,
right: borderPadding,
),
value: value,
onChanged: onChanged,
isDense: isDense,
isExpanded: isExpanded,
borderRadius: BorderRadius.only(
topLeft: selectRadius(showTopLeft),
topRight: selectRadius(showTopRight),
bottomLeft: selectRadius(showBottomLeft),
bottomRight: selectRadius(showBottomRight),
),
style: style,
selectedItemBuilder: selectedItemBuilder,
items: items,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class AnalyticsDropDownButton<T> extends StatelessWidget {
required this.onChanged,
this.sendAnalytics = true,
this.isDense = false,
this.isExpanded = false,
this.roundedCornerOptions,
});

/// The GA ID for the screen this widget is displayed on.
Expand Down Expand Up @@ -50,6 +52,8 @@ class AnalyticsDropDownButton<T> extends StatelessWidget {
final void Function(T?)? onChanged;

final bool isDense;
final bool isExpanded;
final RoundedCornerOptions? roundedCornerOptions;

@override
Widget build(BuildContext context) {
Expand All @@ -59,10 +63,12 @@ class AnalyticsDropDownButton<T> extends StatelessWidget {
message: message,
child: RoundedDropDownButton<T>(
isDense: isDense,
isExpanded: isExpanded,
style: Theme.of(context).textTheme.bodyMedium,
value: value,
items: items?.map((e) => e.item).toList(),
onChanged: _onChanged,
roundedCornerOptions: roundedCornerOptions,
),
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ void main() {
expect(find.byType(ObjectViewport), findsOneWidget);
expect(find.text('Program Explorer'), findsOneWidget);
expect(find.text('Outline'), findsOneWidget);
expect(find.text('Object Store'), findsOneWidget);
expect(find.text('Class Hierarchy'), findsOneWidget);
expect(find.text('No object selected.'), findsOneWidget);
expect(find.byTooltip('Refresh'), findsOneWidget);
},
Expand Down