From 2bb9997223fd1a59413bc1ed98d674d881808749 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Wed, 12 Jul 2023 16:30:08 -0700 Subject: [PATCH 1/3] Debugger panel text selection improvements (#6020) --- .../live_connection/debugger_panel_test.dart | 2 +- packages/devtools_app/lib/src/app.dart | 8 + .../lib/src/screens/debugger/codeview.dart | 51 ++-- .../lib/src/shared/console/console.dart | 78 +++--- .../console/widgets/display_provider.dart | 204 +++++++++++----- .../shared/primitives/selection_controls.dart | 231 ------------------ .../devtools_app/lib/src/shared/tree.dart | 34 +-- .../release_notes/NEXT_RELEASE_NOTES.md | 2 +- .../test/debugger/debugger_screen_test.dart | 2 +- .../debugger_screen_variables_test.dart | 55 ++--- .../test/debugger/variables_test.dart | 7 + 11 files changed, 273 insertions(+), 401 deletions(-) delete mode 100644 packages/devtools_app/lib/src/shared/primitives/selection_controls.dart diff --git a/packages/devtools_app/integration_test/test/live_connection/debugger_panel_test.dart b/packages/devtools_app/integration_test/test/live_connection/debugger_panel_test.dart index 4e9c1ff7231..5965afe6f7f 100644 --- a/packages/devtools_app/integration_test/test/live_connection/debugger_panel_test.dart +++ b/packages/devtools_app/integration_test/test/live_connection/debugger_panel_test.dart @@ -170,7 +170,7 @@ T getWidgetFromFinder(Finder finder) => finder.first.evaluate().first.widget as T; Finder findLineItemWithText(String text) => find.ancestor( - of: find.selectableTextContaining(text), + of: find.textContaining(text), matching: find.byType(LineItem), ); diff --git a/packages/devtools_app/lib/src/app.dart b/packages/devtools_app/lib/src/app.dart index 7bdce798aab..c67ad5545a6 100644 --- a/packages/devtools_app/lib/src/app.dart +++ b/packages/devtools_app/lib/src/app.dart @@ -108,6 +108,14 @@ class DevToolsAppState extends State with AutoDisposeMixin { void initState() { super.initState(); + // TODO(https://github.com/flutter/devtools/issues/6018): Once + // https://github.com/flutter/flutter/issues/129692 is fixed, disable the + // browser's native context menu on secondary-click, and instead use the + // menu provided by Flutter: + // if (kIsWeb) { + // unawaited(BrowserContextMenu.disableContextMenu()); + // } + unawaited(ga.setupDimensions()); addAutoDisposeListener(serviceManager.isolateManager.mainIsolate, () { diff --git a/packages/devtools_app/lib/src/screens/debugger/codeview.dart b/packages/devtools_app/lib/src/screens/debugger/codeview.dart index 226222c05bd..0d84187df36 100644 --- a/packages/devtools_app/lib/src/screens/debugger/codeview.dart +++ b/packages/devtools_app/lib/src/screens/debugger/codeview.dart @@ -1054,29 +1054,31 @@ class _LinesState extends State with AutoDisposeMixin { final pausedFrame = widget.selectedFrameNotifier?.value; final pausedLine = pausedFrame?.line; - return ListView.builder( - controller: widget.scrollController, - physics: const ClampingScrollPhysics(), - itemExtent: CodeView.rowHeight, - itemCount: widget.lines.length, - itemBuilder: (context, index) { - final lineNum = index + 1; - final isPausedLine = pausedLine == lineNum; - return ValueListenableBuilder( - valueListenable: widget.codeViewController.focusLine, - builder: (context, focusLine, _) { - final isFocusedLine = focusLine == lineNum; - return LineItem( - lineContents: widget.lines[index], - pausedFrame: isPausedLine ? pausedFrame : null, - focused: isPausedLine || isFocusedLine, - searchMatches: _searchMatchesForLine(index), - activeSearchMatch: - activeSearch?.position.line == index ? activeSearch : null, - ); - }, - ); - }, + return SelectionArea( + child: ListView.builder( + controller: widget.scrollController, + physics: const ClampingScrollPhysics(), + itemExtent: CodeView.rowHeight, + itemCount: widget.lines.length, + itemBuilder: (context, index) { + final lineNum = index + 1; + final isPausedLine = pausedLine == lineNum; + return ValueListenableBuilder( + valueListenable: widget.codeViewController.focusLine, + builder: (context, focusLine, _) { + final isFocusedLine = focusLine == lineNum; + return LineItem( + lineContents: widget.lines[index], + pausedFrame: isPausedLine ? pausedFrame : null, + focused: isPausedLine || isFocusedLine, + searchMatches: _searchMatchesForLine(index), + activeSearchMatch: + activeSearch?.position.line == index ? activeSearch : null, + ); + }, + ); + }, + ), ); } @@ -1243,9 +1245,8 @@ class _LineItemState extends State enabled: () => true, asyncTimeout: 100, asyncGenerateHoverCardData: _generateHoverCardData, - child: SelectableText.rich( + child: Text.rich( searchAwareLineContents(), - scrollPhysics: const NeverScrollableScrollPhysics(), maxLines: 1, ), ); diff --git a/packages/devtools_app/lib/src/shared/console/console.dart b/packages/devtools_app/lib/src/shared/console/console.dart index 8c60e5ca02f..b6450ce0791 100644 --- a/packages/devtools_app/lib/src/shared/console/console.dart +++ b/packages/devtools_app/lib/src/shared/console/console.dart @@ -179,45 +179,47 @@ class _ConsoleOutputState extends State<_ConsoleOutput> key: _scrollBarKey, child: Padding( padding: const EdgeInsets.symmetric(horizontal: denseSpacing), - child: ListView.separated( - padding: const EdgeInsets.all(denseSpacing), - itemCount: _currentLines.length + (widget.footer != null ? 1 : 0), - controller: _scroll, - // Scroll physics to try to keep content within view and avoid bouncing. - physics: const ClampingScrollPhysics( - parent: RangeMaintainingScrollPhysics(), - ), - separatorBuilder: (_, __) { - return const Divider(); - }, - itemBuilder: (context, index) { - if (index == _currentLines.length && widget.footer != null) { - return widget.footer!; - } - final line = _currentLines[index]; - if (line is TextConsoleLine) { - return SelectableText.rich( - TextSpan( - // TODO(jacobr): consider caching the processed ansi terminal - // codes. - children: processAnsiTerminalCodes( - line.text, - theme.fixedFontStyle, + child: SelectionArea( + child: ListView.separated( + padding: const EdgeInsets.all(denseSpacing), + itemCount: _currentLines.length + (widget.footer != null ? 1 : 0), + controller: _scroll, + // Scroll physics to try to keep content within view and avoid bouncing. + physics: const ClampingScrollPhysics( + parent: RangeMaintainingScrollPhysics(), + ), + separatorBuilder: (_, __) { + return const Divider(); + }, + itemBuilder: (context, index) { + if (index == _currentLines.length && widget.footer != null) { + return widget.footer!; + } + final line = _currentLines[index]; + if (line is TextConsoleLine) { + return Text.rich( + TextSpan( + // TODO(jacobr): consider caching the processed ansi terminal + // codes. + children: processAnsiTerminalCodes( + line.text, + theme.fixedFontStyle, + ), ), - ), - ); - } else if (line is VariableConsoleLine) { - return ExpandableVariable( - variable: line.variable, - ); - } else { - assert( - false, - 'ConsoleLine of unsupported type ${line.runtimeType} encountered', - ); - return const SizedBox(); - } - }, + ); + } else if (line is VariableConsoleLine) { + return ExpandableVariable( + variable: line.variable, + ); + } else { + assert( + false, + 'ConsoleLine of unsupported type ${line.runtimeType} encountered', + ); + return const SizedBox(); + } + }, + ), ), ), ); diff --git a/packages/devtools_app/lib/src/shared/console/widgets/display_provider.dart b/packages/devtools_app/lib/src/shared/console/widgets/display_provider.dart index 3b9845de10d..cbf5ba3c550 100644 --- a/packages/devtools_app/lib/src/shared/console/widgets/display_provider.dart +++ b/packages/devtools_app/lib/src/shared/console/widgets/display_provider.dart @@ -2,37 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart' hide Stack; +import 'package:flutter/services.dart'; import 'package:vm_service/vm_service.dart'; import '../../diagnostics/dart_object_node.dart'; import '../../globals.dart'; -import '../../primitives/selection_controls.dart'; import '../../primitives/utils.dart'; import '../../routing.dart'; import '../../screen.dart'; import '../../theme.dart'; import 'description.dart'; -VariableSelectionControls _selectionControls({ - required DartObjectNode variable, - required Function(TextSelectionDelegate delegate)? onInspect, -}) { - final ref = variable.ref; - return VariableSelectionControls( - onReroot: variable.isRerootable - ? (delegate) { - serviceManager.consoleService.appendBrowsableInstance( - instanceRef: variable.value as InstanceRef?, - isolateRef: ref?.isolateRef, - heapSelection: ref?.heapSelection, - ); - } - : null, - onInspect: onInspect, - ); -} - class DisplayProvider extends StatelessWidget { const DisplayProvider({ super.key, @@ -47,21 +29,18 @@ class DisplayProvider extends StatelessWidget { Widget build(BuildContext context) { final theme = Theme.of(context); - // TODO(devoncarew): Here, we want to wait until the tooltip wants to show, - // then call toString() on variable and render the result in a tooltip. We - // should also include the type of the value in the tooltip if the variable - // is not null. if (variable.text != null) { - return SelectableText.rich( - TextSpan( - children: processAnsiTerminalCodes( - variable.text, - theme.subtleFixedFontStyle, + return InteractivityWrapper( + onTap: onTap, + menuButtons: _getMenuButtons(context), + child: Text.rich( + TextSpan( + children: processAnsiTerminalCodes( + variable.text, + theme.subtleFixedFontStyle, + ), ), ), - onTap: onTap, - selectionControls: - _selectionControls(variable: variable, onInspect: null), ); } final diagnostic = variable.ref?.diagnostic; @@ -74,43 +53,66 @@ class DisplayProvider extends StatelessWidget { } final hasName = variable.name?.isNotEmpty ?? false; - return SelectableText.rich( - TextSpan( - text: hasName ? variable.name : null, - style: variable.artificialName - ? theme.subtleFixedFontStyle - : theme.fixedFontStyle.apply( - color: theme.colorScheme.controlFlowSyntaxColor, + return InteractivityWrapper( + onTap: onTap, + menuButtons: _getMenuButtons(context), + child: Text.rich( + TextSpan( + text: hasName ? variable.name : null, + style: variable.artificialName + ? theme.subtleFixedFontStyle + : theme.fixedFontStyle.apply( + color: theme.colorScheme.controlFlowSyntaxColor, + ), + children: [ + if (hasName) + TextSpan( + text: ': ', + style: theme.fixedFontStyle, ), - children: [ - if (hasName) TextSpan( - text: ': ', - style: theme.fixedFontStyle, + text: variable.displayValue.toString(), + style: variable.artificialValue + ? theme.subtleFixedFontStyle + : _variableDisplayStyle(theme, variable), ), - TextSpan( - text: variable.displayValue.toString(), - style: variable.artificialValue - ? theme.subtleFixedFontStyle - : _variableDisplayStyle(theme, variable), - ), - ], - ), - selectionControls: _selectionControls( - variable: variable, - onInspect: serviceManager.inspectorService == null - ? null - : (delegate) => _handleInspect(delegate, context), + ], + ), ), - onTap: onTap, ); } + List _getMenuButtons( + BuildContext context, + ) { + return [ + if (variable.isRerootable) + ContextMenuButtonItem( + onPressed: () { + ContextMenuController.removeAny(); + final ref = variable.ref; + serviceManager.consoleService.appendBrowsableInstance( + instanceRef: variable.value as InstanceRef?, + isolateRef: ref?.isolateRef, + heapSelection: ref?.heapSelection, + ); + }, + label: 'Reroot', + ), + if (serviceManager.inspectorService != null && variable.isRoot) + ContextMenuButtonItem( + onPressed: () { + ContextMenuController.removeAny(); + _handleInspect(context); + }, + label: 'Inspect', + ), + ]; + } + void _handleInspect( - TextSelectionDelegate delegate, BuildContext context, ) async { - delegate.hideToolbar(); final router = DevToolsRouterDelegate.of(context); final inspectorService = serviceManager.inspectorService; if (await variable.inspectWidget()) { @@ -172,3 +174,87 @@ class DisplayProvider extends StatelessWidget { } } } + +/// A wrapper that allows the user to interact with the variable. +/// +/// Responds to primary and secondary click events. +class InteractivityWrapper extends StatefulWidget { + const InteractivityWrapper({ + super.key, + required this.child, + this.menuButtons, + this.onTap, + }); + + /// Button items shown in a context menu on secondary click. + /// + /// If none are provided, then no action will happen on secondary click. + final List? menuButtons; + + /// Optional callback when tapped. + final void Function()? onTap; + + /// The child widget that will be listened to for gestures. + final Widget child; + + @override + State createState() => _InteractivityWrapperState(); +} + +class _InteractivityWrapperState extends State { + final ContextMenuController _contextMenuController = ContextMenuController(); + + void _onTap() { + ContextMenuController.removeAny(); + final onTap = widget.onTap; + if (onTap != null) { + onTap(); + } + } + + void _onSecondaryTapUp(TapUpDetails details) { + _maybeShowMenu(details.globalPosition); + } + + void _maybeShowMenu(Offset offset) { + // TODO(https://github.com/flutter/devtools/issues/6018): Once + // https://github.com/flutter/flutter/issues/129692 is fixed, disable the + // browser's native context menu on secondary-click, and enable this menu. + if (kIsWeb && BrowserContextMenu.enabled) { + return; + } + + if (_contextMenuController.isShown) { + return; + } + _contextMenuController.show( + context: context, + contextMenuBuilder: (context) { + return AdaptiveTextSelectionToolbar.buttonItems( + anchors: TextSelectionToolbarAnchors(primaryAnchor: offset), + buttonItems: widget.menuButtons, + ); + }, + ); + } + + @override + void dispose() { + _contextMenuController.remove(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final contextMenuOnSecondaryTapEnabled = + widget.menuButtons != null && widget.menuButtons!.isNotEmpty; + + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: _onTap, + onSecondaryTapUp: + contextMenuOnSecondaryTapEnabled ? _onSecondaryTapUp : null, + child: widget.child, + ); + } +} diff --git a/packages/devtools_app/lib/src/shared/primitives/selection_controls.dart b/packages/devtools_app/lib/src/shared/primitives/selection_controls.dart deleted file mode 100644 index f4f73664c98..00000000000 --- a/packages/devtools_app/lib/src/shared/primitives/selection_controls.dart +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// ignore_for_file: deprecated_member_use - -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart' hide Stack; - -/// Android Material styled text selection controls. -class VariableSelectionControls extends MaterialTextSelectionControls { - VariableSelectionControls({ - required this.onInspect, - required this.onReroot, - }); - - final void Function(TextSelectionDelegate delegate)? onInspect; - final void Function(TextSelectionDelegate delegate)? onReroot; - - /// Builder for material-style copy/paste text selection toolbar with added - /// Dart DevTools specific functionality. - @override - Widget buildToolbar( - BuildContext context, - Rect globalEditableRegion, - double textLineHeight, - Offset selectionMidpoint, - List endpoints, - TextSelectionDelegate delegate, - ValueListenable? clipboardStatus, - Offset? lastSecondaryTapDownPosition, - ) { - return _TextSelectionControlsToolbar( - globalEditableRegion: globalEditableRegion, - textLineHeight: textLineHeight, - selectionMidpoint: selectionMidpoint, - endpoints: endpoints, - clipboardStatus: clipboardStatus!, - handleCut: canCut(delegate) ? () => handleCut(delegate) : null, - handleCopy: canCopy(delegate) ? () => handleCopy(delegate) : null, - handlePaste: - canPaste(delegate) ? () => unawaited(handlePaste(delegate)) : null, - handleSelectAll: - canSelectAll(delegate) ? () => handleSelectAll(delegate) : null, - handleInspect: onInspect != null ? () => onInspect!(delegate) : null, - handleReroot: onReroot != null ? () => onReroot!(delegate) : null, - ); - } -} - -/// The highest level toolbar widget, built directly by buildToolbar. -class _TextSelectionControlsToolbar extends StatefulWidget { - const _TextSelectionControlsToolbar({ - Key? key, - required this.clipboardStatus, - required this.endpoints, - required this.globalEditableRegion, - required this.handleInspect, - required this.handleReroot, - required this.handleCut, - required this.handleCopy, - required this.handlePaste, - required this.handleSelectAll, - required this.selectionMidpoint, - required this.textLineHeight, - }) : super(key: key); - - final ValueListenable clipboardStatus; - final List endpoints; - final Rect globalEditableRegion; - final VoidCallback? handleInspect; - final VoidCallback? handleReroot; - final VoidCallback? handleCut; - final VoidCallback? handleCopy; - final VoidCallback? handlePaste; - final VoidCallback? handleSelectAll; - final Offset selectionMidpoint; - final double textLineHeight; - - @override - _TextSelectionControlsToolbarState createState() => - _TextSelectionControlsToolbarState(); -} - -class _TextSelectionControlsToolbarState - extends State<_TextSelectionControlsToolbar> with TickerProviderStateMixin { - void _onChangedClipboardStatus() { - setState(() { - // Inform the widget that the value of clipboardStatus has changed. - }); - } - - @override - void initState() { - super.initState(); - widget.clipboardStatus.addListener(_onChangedClipboardStatus); - } - - @override - void didUpdateWidget(_TextSelectionControlsToolbar oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.clipboardStatus != oldWidget.clipboardStatus) { - widget.clipboardStatus.addListener(_onChangedClipboardStatus); - oldWidget.clipboardStatus.removeListener(_onChangedClipboardStatus); - } - } - - @override - void dispose() { - super.dispose(); - widget.clipboardStatus.removeListener(_onChangedClipboardStatus); - } - - @override - Widget build(BuildContext context) { - // If there are no buttons to be shown, don't render anything. - if (widget.handleCut == null && - widget.handleCopy == null && - widget.handlePaste == null && - widget.handleSelectAll == null) { - return const SizedBox.shrink(); - } - // If the paste button is desired, don't render anything until the state of - // the clipboard is known, since it's used to determine if paste is shown. - if (widget.handlePaste != null && - widget.clipboardStatus.value == ClipboardStatus.unknown) { - return const SizedBox.shrink(); - } - - // Calculate the positioning of the menu. It is placed above the selection - // if there is enough room, or otherwise below. - final startTextSelectionPoint = widget.endpoints[0]; - final endTextSelectionPoint = - widget.endpoints.length > 1 ? widget.endpoints[1] : widget.endpoints[0]; - final anchorAbove = Offset( - widget.globalEditableRegion.left + widget.selectionMidpoint.dx, - widget.globalEditableRegion.top + - startTextSelectionPoint.point.dy - - widget.textLineHeight - - _kToolbarContentDistance, - ); - final anchorBelow = Offset( - widget.globalEditableRegion.left + widget.selectionMidpoint.dx, - widget.globalEditableRegion.top + - endTextSelectionPoint.point.dy + - _kToolbarContentDistanceBelow, - ); - - // Determine which buttons will appear so that the order and total number is - // known. A button's position in the menu can slightly affect its - // appearance. - assert(debugCheckHasMaterialLocalizations(context)); - final localizations = MaterialLocalizations.of(context); - final itemDatas = <_TextSelectionToolbarItemData>[ - if (widget.handleInspect != null) - _TextSelectionToolbarItemData( - label: 'Inspect', - onPressed: widget.handleInspect, - ), - if (widget.handleReroot != null) - _TextSelectionToolbarItemData( - label: 'Reroot', - onPressed: widget.handleReroot, - ), - if (widget.handleCut != null) - _TextSelectionToolbarItemData( - label: localizations.cutButtonLabel, - onPressed: widget.handleCut, - ), - if (widget.handleCopy != null) - _TextSelectionToolbarItemData( - label: localizations.copyButtonLabel, - onPressed: widget.handleCopy, - ), - if (widget.handlePaste != null && - widget.clipboardStatus.value == ClipboardStatus.pasteable) - _TextSelectionToolbarItemData( - label: localizations.pasteButtonLabel, - onPressed: widget.handlePaste, - ), - if (widget.handleSelectAll != null) - _TextSelectionToolbarItemData( - label: localizations.selectAllButtonLabel, - onPressed: widget.handleSelectAll, - ), - ]; - - // If there is no option available, build an empty widget. - if (itemDatas.isEmpty) { - return const SizedBox(width: 0.0, height: 0.0); - } - - return TextSelectionToolbar( - anchorAbove: anchorAbove, - anchorBelow: anchorBelow, - children: itemDatas - .asMap() - .entries - .map((MapEntry entry) { - return TextSelectionToolbarTextButton( - padding: TextSelectionToolbarTextButton.getPadding( - entry.key, - itemDatas.length, - ), - onPressed: entry.value.onPressed, - child: Text(entry.value.label), - ); - }).toList(), - ); - } -} - -// Forked from material/text_selection.dart -const double _kHandleSize = 22.0; - -// Padding between the toolbar and the anchor. -const double _kToolbarContentDistanceBelow = _kHandleSize - 2.0; -const double _kToolbarContentDistance = 8.0; - -/// The label and callback for the available default text selection menu buttons. -class _TextSelectionToolbarItemData { - const _TextSelectionToolbarItemData({ - required this.label, - required this.onPressed, - }); - - final String label; - final VoidCallback? onPressed; -} diff --git a/packages/devtools_app/lib/src/shared/tree.dart b/packages/devtools_app/lib/src/shared/tree.dart index b8f9d0c9b5a..7f9d0500e9b 100644 --- a/packages/devtools_app/lib/src/shared/tree.dart +++ b/packages/devtools_app/lib/src/shared/tree.dart @@ -82,22 +82,24 @@ class _TreeViewState> extends State> @override Widget build(BuildContext context) { if (dataFlatList.isEmpty) return _emptyTreeViewBuilder(); - final content = ListView.builder( - itemCount: dataFlatList.length, - itemExtent: widget.itemExtent, - shrinkWrap: widget.shrinkWrap, - physics: widget.shrinkWrap ? const ClampingScrollPhysics() : null, - controller: widget.scrollController, - itemBuilder: (context, index) { - final T item = dataFlatList[index]; - return _TreeViewItem( - item, - buildDisplay: (onPressed) => - widget.dataDisplayProvider(item, onPressed), - onItemSelected: _onItemSelected, - onItemExpanded: _onItemExpanded, - ); - }, + final content = SelectionArea( + child: ListView.builder( + itemCount: dataFlatList.length, + itemExtent: widget.itemExtent, + shrinkWrap: widget.shrinkWrap, + physics: widget.shrinkWrap ? const ClampingScrollPhysics() : null, + controller: widget.scrollController, + itemBuilder: (context, index) { + final T item = dataFlatList[index]; + return _TreeViewItem( + item, + buildDisplay: (onPressed) => + widget.dataDisplayProvider(item, onPressed), + onItemSelected: _onItemSelected, + onItemExpanded: _onItemExpanded, + ); + }, + ), ); if (widget.includeScrollbar) { return Scrollbar( diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md index d3b7608a9d9..bee33850eb5 100644 --- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md +++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md @@ -29,7 +29,7 @@ TODO: Remove this section if there are not any general updates. * Warn users when HTTP logging may be affecting their app's memory consumption - [#5998](https://github.com/flutter/devtools/pull/5998) ## Debugger updates -TODO: Remove this section if there are not any general updates. +* Improvements to text selection and copy behavior in the codeview, console, and variables window. - [#6020](https://github.com/flutter/devtools/pull/6020) ## Network profiler updates * Added a selector to customize the display type of text and json responses (thanks to @hhacker1999!) - [#5816](https://github.com/flutter/devtools/pull/5816) diff --git a/packages/devtools_app/test/debugger/debugger_screen_test.dart b/packages/devtools_app/test/debugger/debugger_screen_test.dart index 5abede206dc..678cd8c42ed 100644 --- a/packages/devtools_app/test/debugger/debugger_screen_test.dart +++ b/packages/devtools_app/test/debugger/debugger_screen_test.dart @@ -105,7 +105,7 @@ void main() { expect(find.text('Console'), findsOneWidget); // test for stdio output. - expect(find.selectableText('test stdio'), findsOneWidget); + expect(find.text('test stdio'), findsOneWidget); }, ); diff --git a/packages/devtools_app/test/debugger/debugger_screen_variables_test.dart b/packages/devtools_app/test/debugger/debugger_screen_variables_test.dart index 0c26f4a5c6e..61d4cb987c0 100644 --- a/packages/devtools_app/test/debugger/debugger_screen_variables_test.dart +++ b/packages/devtools_app/test/debugger/debugger_screen_variables_test.dart @@ -60,17 +60,14 @@ void main() { WidgetTester tester, { required Finder parentFinder, }) async { - final group0To9999Finder = find.selectableTextContaining('[0 - 9999]'); - final group10000To19999Finder = - find.selectableTextContaining('[10000 - 19999]'); - final group230000To239999Finder = - find.selectableTextContaining('[230000 - 239999]'); - final group240000To243620Finder = - find.selectableTextContaining('[240000 - 243620]'); - - final group0To99Finder = find.selectableTextContaining('[0 - 99]'); - final group100To199Finder = find.selectableTextContaining('[100 - 199]'); - final group200To299Finder = find.selectableTextContaining('[200 - 299]'); + final group0To9999Finder = find.textContaining('[0 - 9999]'); + final group10000To19999Finder = find.textContaining('[10000 - 19999]'); + final group230000To239999Finder = find.textContaining('[230000 - 239999]'); + final group240000To243620Finder = find.textContaining('[240000 - 243620]'); + + final group0To99Finder = find.textContaining('[0 - 99]'); + final group100To199Finder = find.textContaining('[100 - 199]'); + final group200To299Finder = find.textContaining('[200 - 299]'); // Initially the parent variable is not expanded. expect(parentFinder, findsOneWidget); @@ -116,36 +113,36 @@ void main() { await pumpDebuggerScreen(tester, debuggerController); expect(find.text('Variables'), findsOneWidget); - final listFinder = find.selectableText('Root 1: List (2 items)'); + final listFinder = find.text('Root 1: List (2 items)'); expect(listFinder, findsOneWidget); - final mapFinder = find.selectableTextContaining( + final mapFinder = find.textContaining( 'Root 2: Map (2 items)', ); - final mapElement1Finder = find.selectableTextContaining("['key1']: 1.0"); - final mapElement2Finder = find.selectableTextContaining("['key2']: 2.0"); + final mapElement1Finder = find.textContaining("['key1']: 1.0"); + final mapElement2Finder = find.textContaining("['key2']: 2.0"); expect(listFinder, findsOneWidget); expect(mapFinder, findsOneWidget); expect( - find.selectableTextContaining("Root 3: 'test str...'"), + find.textContaining("Root 3: 'test str...'"), findsOneWidget, ); expect( - find.selectableTextContaining('Root 4: true'), + find.textContaining('Root 4: true'), findsOneWidget, ); // Initially list is not expanded. - expect(find.selectableTextContaining('0: 3'), findsNothing); - expect(find.selectableTextContaining('1: 4'), findsNothing); + expect(find.textContaining('0: 3'), findsNothing); + expect(find.textContaining('1: 4'), findsNothing); // Expand list. await tester.tap(listFinder); await tester.pump(); - expect(find.selectableTextContaining('0: 0'), findsOneWidget); - expect(find.selectableTextContaining('1: 1'), findsOneWidget); + expect(find.textContaining('0: 0'), findsOneWidget); + expect(find.textContaining('1: 1'), findsOneWidget); // Initially map is not expanded. expect(mapElement1Finder, findsNothing); @@ -158,18 +155,18 @@ void main() { expect(mapElement2Finder, findsOneWidget); // Expect a tooltip for the set instance. - final setFinder = find.selectableText('Root 5: Set (2 items)'); + final setFinder = find.text('Root 5: Set (2 items)'); expect(setFinder, findsOneWidget); // Initially set is not expanded. - expect(find.selectableTextContaining('set value 0'), findsNothing); - expect(find.selectableTextContaining('set value 1'), findsNothing); + expect(find.textContaining('set value 0'), findsNothing); + expect(find.textContaining('set value 1'), findsNothing); // Expand set await tester.tap(setFinder); await tester.pump(); - expect(find.selectableTextContaining('set value 0'), findsOneWidget); - expect(find.selectableTextContaining('set value 1'), findsOneWidget); + expect(find.textContaining('set value 0'), findsOneWidget); + expect(find.textContaining('set value 1'), findsOneWidget); }, ); @@ -185,7 +182,7 @@ void main() { await pumpDebuggerScreen(tester, debuggerController); - final listFinder = find.selectableText('Root 1: List (243,621 items)'); + final listFinder = find.text('Root 1: List (243,621 items)'); await verifyGroupings(tester, parentFinder: listFinder); }, ); @@ -202,7 +199,7 @@ void main() { await pumpDebuggerScreen(tester, debuggerController); - final mapFinder = find.selectableText('Root 1: Map (243,621 items)'); + final mapFinder = find.text('Root 1: Map (243,621 items)'); await verifyGroupings(tester, parentFinder: mapFinder); }, ); @@ -219,7 +216,7 @@ void main() { await pumpDebuggerScreen(tester, debuggerController); - final setFinder = find.selectableText('Root 1: Set (243,621 items)'); + final setFinder = find.text('Root 1: Set (243,621 items)'); await verifyGroupings(tester, parentFinder: setFinder); }, ); diff --git a/packages/devtools_app/test/debugger/variables_test.dart b/packages/devtools_app/test/debugger/variables_test.dart index 25043a41b5b..522a4251796 100644 --- a/packages/devtools_app/test/debugger/variables_test.dart +++ b/packages/devtools_app/test/debugger/variables_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:devtools_app/src/service/service_manager.dart'; import 'package:devtools_app/src/shared/config_specific/ide_theme/ide_theme.dart'; import 'package:devtools_app/src/shared/console/widgets/expandable_variable.dart'; import 'package:devtools_app/src/shared/diagnostics/dart_object_node.dart'; @@ -11,6 +12,12 @@ import 'package:devtools_test/devtools_test.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { + setUp(() { + final service = createMockVmServiceWrapperWithDefaults(); + final manager = FakeServiceManager(service: service); + setGlobal(ServiceConnectionManager, manager); + }); + group('debugger variables', () { late DartObjectNode objectNode; From 2a106f3bda53d6925a55599060a4cd7b29933229 Mon Sep 17 00:00:00 2001 From: DartDevtoolWorkflowBot <121203384+DartDevtoolWorkflowBot@users.noreply.github.com> Date: Thu, 13 Jul 2023 04:38:38 -0400 Subject: [PATCH 2/3] Updating from 2.26.0-dev.0 to 2.26.0-dev.1 (#6029) Automated Version Bump --- packages/devtools_app/lib/devtools.dart | 2 +- packages/devtools_app/pubspec.yaml | 6 +++--- packages/devtools_shared/pubspec.yaml | 2 +- packages/devtools_test/pubspec.yaml | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/devtools_app/lib/devtools.dart b/packages/devtools_app/lib/devtools.dart index a23654ced93..87dfd6a0d46 100644 --- a/packages/devtools_app/lib/devtools.dart +++ b/packages/devtools_app/lib/devtools.dart @@ -9,4 +9,4 @@ // the constant declaration `const String version =`. // If you change the declaration you must also modify the regex in // tools/update_version.dart. -const String version = '2.26.0-dev.0'; +const String version = '2.26.0-dev.1'; diff --git a/packages/devtools_app/pubspec.yaml b/packages/devtools_app/pubspec.yaml index aaa40ed315b..7bfe1932303 100644 --- a/packages/devtools_app/pubspec.yaml +++ b/packages/devtools_app/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: none # Note: this version should only be updated by running tools/update_version.dart # that updates all versions of devtools packages (devtools_app, devtools_test). -version: 2.26.0-dev.0 +version: 2.26.0-dev.1 repository: https://github.com/flutter/devtools/tree/master/packages/devtools_app @@ -24,7 +24,7 @@ dependencies: codicon: ^1.0.0 collection: ^1.15.0 dds_service_extensions: ^1.3.2 - devtools_shared: 2.26.0-dev.0 + devtools_shared: 2.26.0-dev.1 file: ^6.0.0 file_selector: ^0.8.0 file_selector_linux: ^0.0.2 @@ -66,7 +66,7 @@ dependencies: dev_dependencies: args: ^2.4.2 build_runner: ^2.3.3 - devtools_test: 2.26.0-dev.0 + devtools_test: 2.26.0-dev.1 fake_async: ^1.3.1 flutter_driver: sdk: flutter diff --git a/packages/devtools_shared/pubspec.yaml b/packages/devtools_shared/pubspec.yaml index e8397b32319..b0536548ca4 100644 --- a/packages/devtools_shared/pubspec.yaml +++ b/packages/devtools_shared/pubspec.yaml @@ -1,7 +1,7 @@ name: devtools_shared description: Package of shared structures between devtools_app, dds, and other tools. -version: 2.26.0-dev.0 +version: 2.26.0-dev.1 repository: https://github.com/flutter/devtools/tree/master/packages/devtools_shared diff --git a/packages/devtools_test/pubspec.yaml b/packages/devtools_test/pubspec.yaml index 794d75703bd..2e65bb97d5c 100644 --- a/packages/devtools_test/pubspec.yaml +++ b/packages/devtools_test/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # When publishing new versions of this package be sure to publish a new version # of package:devtools as well. package:devtools contains a compiled snapshot of # this package. -version: 2.26.0-dev.0 +version: 2.26.0-dev.1 repository: https://github.com/flutter/devtools/tree/master/packages/devtools_test @@ -18,8 +18,8 @@ environment: dependencies: async: ^2.0.0 collection: ^1.15.0 - devtools_shared: 2.26.0-dev.0 - devtools_app: 2.26.0-dev.0 + devtools_shared: 2.26.0-dev.1 + devtools_app: 2.26.0-dev.1 flutter: sdk: flutter flutter_test: From 5b08bf3aa7d7c12b9343df9cbc23d993fdf53f87 Mon Sep 17 00:00:00 2001 From: DartDevtoolWorkflowBot <121203384+DartDevtoolWorkflowBot@users.noreply.github.com> Date: Fri, 14 Jul 2023 04:35:28 -0400 Subject: [PATCH 3/3] Updating from 2.26.0-dev.1 to 2.26.0-dev.2 (#6033) Automated Version Bump --- packages/devtools_app/lib/devtools.dart | 2 +- packages/devtools_app/pubspec.yaml | 6 +++--- packages/devtools_shared/pubspec.yaml | 2 +- packages/devtools_test/pubspec.yaml | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/devtools_app/lib/devtools.dart b/packages/devtools_app/lib/devtools.dart index 87dfd6a0d46..1e66b618ae5 100644 --- a/packages/devtools_app/lib/devtools.dart +++ b/packages/devtools_app/lib/devtools.dart @@ -9,4 +9,4 @@ // the constant declaration `const String version =`. // If you change the declaration you must also modify the regex in // tools/update_version.dart. -const String version = '2.26.0-dev.1'; +const String version = '2.26.0-dev.2'; diff --git a/packages/devtools_app/pubspec.yaml b/packages/devtools_app/pubspec.yaml index 7bfe1932303..0dae12754f4 100644 --- a/packages/devtools_app/pubspec.yaml +++ b/packages/devtools_app/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: none # Note: this version should only be updated by running tools/update_version.dart # that updates all versions of devtools packages (devtools_app, devtools_test). -version: 2.26.0-dev.1 +version: 2.26.0-dev.2 repository: https://github.com/flutter/devtools/tree/master/packages/devtools_app @@ -24,7 +24,7 @@ dependencies: codicon: ^1.0.0 collection: ^1.15.0 dds_service_extensions: ^1.3.2 - devtools_shared: 2.26.0-dev.1 + devtools_shared: 2.26.0-dev.2 file: ^6.0.0 file_selector: ^0.8.0 file_selector_linux: ^0.0.2 @@ -66,7 +66,7 @@ dependencies: dev_dependencies: args: ^2.4.2 build_runner: ^2.3.3 - devtools_test: 2.26.0-dev.1 + devtools_test: 2.26.0-dev.2 fake_async: ^1.3.1 flutter_driver: sdk: flutter diff --git a/packages/devtools_shared/pubspec.yaml b/packages/devtools_shared/pubspec.yaml index b0536548ca4..38ff43a8230 100644 --- a/packages/devtools_shared/pubspec.yaml +++ b/packages/devtools_shared/pubspec.yaml @@ -1,7 +1,7 @@ name: devtools_shared description: Package of shared structures between devtools_app, dds, and other tools. -version: 2.26.0-dev.1 +version: 2.26.0-dev.2 repository: https://github.com/flutter/devtools/tree/master/packages/devtools_shared diff --git a/packages/devtools_test/pubspec.yaml b/packages/devtools_test/pubspec.yaml index 2e65bb97d5c..3eda17b8866 100644 --- a/packages/devtools_test/pubspec.yaml +++ b/packages/devtools_test/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: none # When publishing new versions of this package be sure to publish a new version # of package:devtools as well. package:devtools contains a compiled snapshot of # this package. -version: 2.26.0-dev.1 +version: 2.26.0-dev.2 repository: https://github.com/flutter/devtools/tree/master/packages/devtools_test @@ -18,8 +18,8 @@ environment: dependencies: async: ^2.0.0 collection: ^1.15.0 - devtools_shared: 2.26.0-dev.1 - devtools_app: 2.26.0-dev.1 + devtools_shared: 2.26.0-dev.2 + devtools_app: 2.26.0-dev.2 flutter: sdk: flutter flutter_test: