Skip to content
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 @@ -24,54 +24,45 @@ class DebugSessions extends StatelessWidget {
children: [
Text(
'Debug Sessions',
style: Theme.of(context).textTheme.titleSmall,
style: Theme.of(context).textTheme.titleMedium,
),
if (sessions.isEmpty)
const Text('Begin a debug session to use DevTools.')
else
Table(
columnWidths: const {
0: FlexColumnWidth(2),
// TODO(dantup): Fixed width icons+menu?
1: FlexColumnWidth(),
0: FlexColumnWidth(),
},
defaultColumnWidth:
FixedColumnWidth(actionsIconSize + denseSpacing),
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: [
for (final session in sessions)
TableRow(
children: [
Text(
'${session.name} (${session.flutterMode})',
style: Theme.of(context).textTheme.titleSmall,
),
if (api.capabilities.openDevToolsPage)
_DevToolsMenu(api: api, session: session),
],
),
_debugSessionRow(session, context),
],
),
],
);
}
}

class _DevToolsMenu extends StatelessWidget {
const _DevToolsMenu({required this.api, required this.session});

final VsCodeApi api;
final VsCodeDebugSession session;

@override
Widget build(BuildContext context) {
TableRow _debugSessionRow(VsCodeDebugSession session, BuildContext context) {
// TODO(dantup): What to show if mode is unknown (null)?
final mode = session.flutterMode;
final isDebug = mode == 'debug';
final isProfile = mode == 'profile';
// final isRelease = mode == 'release' || mode == 'jit_release';
final isFlutter = session.debuggerType?.contains('Flutter') ?? false;

return MenuBar(
final label = session.flutterMode != null
? '${session.name} (${session.flutterMode})'
: session.name;

return TableRow(
children: [
Text(
label,
style: Theme.of(context).regularTextStyle,
),
IconButton(
onPressed: api.capabilities.hotReload && (isDebug || !isFlutter)
? () => unawaited(api.hotReload(session.id))
Expand All @@ -86,53 +77,118 @@ class _DevToolsMenu extends StatelessWidget {
tooltip: 'Hot Restart',
icon: Icon(hotRestartIcon, size: actionsIconSize),
),
SubmenuButton(
menuChildren: [
// TODO(dantup): Ensure the order matches the DevTools tab bar (if
// possible, share this order).
// TODO(dantup): Make these conditions use the real screen
// conditions and/or verify if these conditions are correct.
_devToolsButton(
ScreenMetaData.inspector,
enabled: isFlutter && isDebug,
),
_devToolsButton(
ScreenMetaData.cpuProfiler,
enabled: isDebug || isProfile,
),
_devToolsButton(
ScreenMetaData.memory,
enabled: isDebug || isProfile,
),
_devToolsButton(
ScreenMetaData.performance,
),
_devToolsButton(
ScreenMetaData.network,
enabled: isDebug,
),
_devToolsButton(
ScreenMetaData.logging,
),
// TODO(dantup): Check other screens (like appSize) work embedded and
// add here.
],
child: const Text('DevTools'),
),
if (api.capabilities.openDevToolsPage)
_DevToolsMenu(
api: api,
session: session,
isFlutter: isFlutter,
isDebug: isDebug,
isProfile: isProfile,
),
],
);
}
}

class _DevToolsMenu extends StatelessWidget {
const _DevToolsMenu({
required this.api,
required this.session,
required this.isFlutter,
required this.isDebug,
required this.isProfile,
});

final VsCodeApi api;
final VsCodeDebugSession session;
final bool isFlutter;
final bool isDebug;
final bool isProfile;

@override
Widget build(BuildContext context) {
final normalDirection = Directionality.of(context);
final reversedDirection = normalDirection == TextDirection.ltr
? TextDirection.rtl
: TextDirection.ltr;

Widget devToolsButton(
ScreenMetaData screen, {
bool enabled = true,
}) {
return SizedBox(
width: double.infinity,
child: TextButton.icon(
style: TextButton.styleFrom(
alignment: Alignment.centerRight,
shape: const ContinuousRectangleBorder(),
),
onPressed: enabled
? () => unawaited(api.openDevToolsPage(session.id, screen.id))
: null,
label: Directionality(
textDirection: normalDirection,
child: Text(screen.title ?? screen.id),
),
icon: Icon(screen.icon, size: actionsIconSize),
),
);
}

Widget _devToolsButton(
ScreenMetaData screen, {
bool enabled = true,
}) {
return IconButton(
onPressed: enabled
? () => unawaited(api.openDevToolsPage(session.id, screen.id))
: null,
tooltip: screen.title ?? screen.id,
icon: Icon(screen.icon, size: actionsIconSize),
return Directionality(
// Reverse the direction so the menu is anchored on the far side and
// expands in the opposite direction with the icons on the right.
textDirection: reversedDirection,
child: MenuAnchor(
style: const MenuStyle(
alignment: AlignmentDirectional.bottomStart,
),
menuChildren: [
// TODO(dantup): Ensure the order matches the DevTools tab bar (if
// possible, share this order).
Comment on lines +147 to +148
Copy link
Member

Choose a reason for hiding this comment

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

Checkout the ScreenMetaData enum in screen.dart. We can try to match the order there. If we do this, we should also add a test to visible_screens_test.dart that ensures that the order of DevTools screens matches the order specified in the enum.

// TODO(dantup): Make these conditions use the real screen
// conditions and/or verify if these conditions are correct.
devToolsButton(
ScreenMetaData.inspector,
enabled: isFlutter && isDebug,
),
devToolsButton(
ScreenMetaData.cpuProfiler,
enabled: isDebug || isProfile,
),
devToolsButton(
ScreenMetaData.memory,
enabled: isDebug || isProfile,
),
devToolsButton(
ScreenMetaData.performance,
),
devToolsButton(
ScreenMetaData.network,
enabled: isDebug,
),
devToolsButton(
ScreenMetaData.logging,
),
// TODO(dantup): Check other screens (like appSize) work embedded and
// add here.
],
builder: (context, controller, child) => IconButton(
onPressed: () {
if (controller.isOpen) {
controller.close();
} else {
controller.open();
}
},
tooltip: 'DevTools',
// TODO(dantup): Icon for DevTools menu?
icon: Icon(
Icons.construction,
size: actionsIconSize,
),
),
),
);
}
}
35 changes: 24 additions & 11 deletions packages/devtools_app/lib/src/standalone_ui/vs_code/devices.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:async';

import 'package:devtools_app_shared/ui.dart';
import 'package:flutter/material.dart';

import '../api/vs_code_api.dart';
Expand All @@ -22,25 +23,23 @@ class Devices extends StatelessWidget {

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Devices',
style: Theme.of(context).textTheme.titleSmall,
style: theme.textTheme.titleMedium,
),
if (devices.isEmpty)
const Text('Connect a device or enable web/desktop platforms.')
else
Table(
columnWidths: const {
0: FlexColumnWidth(3),
1: FlexColumnWidth(),
},
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: [
for (final device in devices)
_createDeviceRow(
theme,
device,
isSelected: device.id == selectedDeviceId,
),
Expand All @@ -50,18 +49,32 @@ class Devices extends StatelessWidget {
);
}

TableRow _createDeviceRow(VsCodeDevice device, {required bool isSelected}) {
TableRow _createDeviceRow(
ThemeData theme,
VsCodeDevice device, {
required bool isSelected,
}) {
final backgroundColor = isSelected ? theme.colorScheme.primary : null;
final foregroundColor = isSelected ? theme.colorScheme.onPrimary : null;

return TableRow(
decoration: BoxDecoration(color: backgroundColor),
children: [
Align(
alignment: Alignment.centerLeft,
SizedBox(
width: double.infinity,
child: TextButton(
child: Text(device.name),
style: TextButton.styleFrom(
alignment: Alignment.centerLeft,
shape: const ContinuousRectangleBorder(),
textStyle: theme.regularTextStyle,
),
child: Text(
device.name,
style: theme.regularTextStyle.copyWith(color: foregroundColor),
),
onPressed: () => unawaited(api.selectDevice(device.id)),
),
),
// TODO(dantup): Use a highlighted/select row for this instead of text.
Text(isSelected ? 'current device' : ''),
],
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class MockDartToolingApi extends DartToolingApiImpl {
server.registerMethod('vsCode.executeCommand', executeCommand);
server.registerMethod('vsCode.selectDevice', selectDevice);
server.registerMethod('vsCode.openDevToolsPage', noOpHandler);
server.registerMethod('vsCode.hotReload', noOpHandler);
server.registerMethod('vsCode.hotRestart', noOpHandler);
}

final json_rpc_2.Peer client;
Expand Down