-
Notifications
You must be signed in to change notification settings - Fork 337
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
371 additions
and
309 deletions.
There are no files selected for viewing
66 changes: 66 additions & 0 deletions
66
packages/devtools_app/lib/src/screens/logging/_kind_column.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright 2019 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. | ||
|
||
// @dart=2.9 | ||
|
||
import 'package:flutter/material.dart'; | ||
|
||
import '../../shared/table.dart'; | ||
import '../../shared/table_data.dart'; | ||
import '../../shared/theme.dart'; | ||
import '../../shared/utils.dart'; | ||
import 'logging_controller.dart'; | ||
|
||
class KindColumn extends ColumnData<LogData> | ||
implements ColumnRenderer<LogData> { | ||
KindColumn() | ||
: super( | ||
'Kind', | ||
fixedWidthPx: scaleByFontFactor(155), | ||
); | ||
|
||
@override | ||
bool get supportsSorting => false; | ||
|
||
@override | ||
String getValue(LogData dataObject) => dataObject.kind; | ||
|
||
@override | ||
Widget build( | ||
BuildContext context, | ||
LogData item, { | ||
bool isRowSelected = false, | ||
VoidCallback onPressed, | ||
}) { | ||
final String kind = item.kind; | ||
|
||
Color color = const Color.fromARGB(0xff, 0x61, 0x61, 0x61); | ||
|
||
if (kind == 'stderr' || item.isError || kind == 'flutter.error') { | ||
color = const Color.fromARGB(0xff, 0xF4, 0x43, 0x36); | ||
} else if (kind == 'stdout') { | ||
color = const Color.fromARGB(0xff, 0x78, 0x90, 0x9C); | ||
} else if (kind.startsWith('flutter')) { | ||
color = const Color.fromARGB(0xff, 0x00, 0x91, 0xea); | ||
} else if (kind == 'gc') { | ||
color = const Color.fromARGB(0xff, 0x42, 0x42, 0x42); | ||
} | ||
|
||
// Use a font color that contrasts with the colored backgrounds. | ||
final textStyle = Theme.of(context).fixedFontStyle; | ||
|
||
return Container( | ||
padding: const EdgeInsets.symmetric(horizontal: 3.0), | ||
decoration: BoxDecoration( | ||
color: color, | ||
borderRadius: BorderRadius.circular(3.0), | ||
), | ||
child: Text( | ||
kind, | ||
overflow: TextOverflow.ellipsis, | ||
style: textStyle, | ||
), | ||
); | ||
} | ||
} |
111 changes: 111 additions & 0 deletions
111
packages/devtools_app/lib/src/screens/logging/_log_details.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// Copyright 2019 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. | ||
|
||
// @dart=2.9 | ||
|
||
import 'package:flutter/material.dart'; | ||
|
||
import '../../shared/common_widgets.dart'; | ||
import '../../shared/console.dart'; | ||
import '../../shared/theme.dart'; | ||
import 'logging_controller.dart'; | ||
|
||
class LogDetails extends StatefulWidget { | ||
const LogDetails({Key key, @required this.log}) : super(key: key); | ||
|
||
final LogData log; | ||
|
||
@override | ||
_LogDetailsState createState() => _LogDetailsState(); | ||
|
||
static const copyToClipboardButtonKey = | ||
Key('log_details_copy_to_clipboard_button'); | ||
} | ||
|
||
class _LogDetailsState extends State<LogDetails> | ||
with SingleTickerProviderStateMixin { | ||
String _lastDetails; | ||
ScrollController scrollController; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
scrollController = ScrollController(); | ||
_computeLogDetails(); | ||
} | ||
|
||
@override | ||
void didUpdateWidget(LogDetails oldWidget) { | ||
super.didUpdateWidget(oldWidget); | ||
if (widget.log != oldWidget.log) { | ||
_computeLogDetails(); | ||
} | ||
} | ||
|
||
Future<void> _computeLogDetails() async { | ||
if (widget.log?.needsComputing ?? false) { | ||
await widget.log.compute(); | ||
setState(() {}); | ||
} | ||
} | ||
|
||
bool showSimple(LogData log) => log != null && !log.needsComputing; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Container( | ||
child: _buildContent(context, widget.log), | ||
); | ||
} | ||
|
||
Widget _buildContent(BuildContext context, LogData log) { | ||
// TODO(#1370): Handle showing flutter errors in a structured manner. | ||
return Stack( | ||
children: [ | ||
_buildSimpleLog(context, log), | ||
if (log != null && log.needsComputing) | ||
const CenteredCircularProgressIndicator(), | ||
], | ||
); | ||
} | ||
|
||
Widget _buildSimpleLog(BuildContext context, LogData log) { | ||
final disabled = log?.details == null || log.details.isEmpty; | ||
|
||
final details = log?.details; | ||
if (details != _lastDetails) { | ||
if (scrollController.hasClients) { | ||
// Make sure we change the scroll if the log details shown have changed. | ||
scrollController.jumpTo(0); | ||
} | ||
_lastDetails = details; | ||
} | ||
|
||
return OutlineDecoration( | ||
child: ConsoleFrame( | ||
title: AreaPaneHeader( | ||
title: const Text('Details'), | ||
needsTopBorder: false, | ||
rightActions: [ | ||
CopyToClipboardControl( | ||
dataProvider: disabled ? null : () => log?.prettyPrinted, | ||
buttonKey: LogDetails.copyToClipboardButtonKey, | ||
), | ||
], | ||
), | ||
child: Padding( | ||
padding: const EdgeInsets.all(denseSpacing), | ||
child: SingleChildScrollView( | ||
controller: scrollController, | ||
child: SelectableText( | ||
log?.prettyPrinted ?? '', | ||
textAlign: TextAlign.left, | ||
style: Theme.of(context).fixedFontStyle, | ||
), | ||
), | ||
), | ||
), | ||
); | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
packages/devtools_app/lib/src/screens/logging/_logs_table.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright 2019 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. | ||
|
||
// @dart=2.9 | ||
|
||
import 'package:flutter/foundation.dart'; | ||
import 'package:flutter/material.dart'; | ||
|
||
import '../../primitives/utils.dart'; | ||
import '../../shared/table.dart'; | ||
import '../../shared/table_data.dart'; | ||
import '_kind_column.dart'; | ||
import '_message_column.dart'; | ||
import '_when_column.dart'; | ||
import 'logging_controller.dart'; | ||
|
||
class LogsTable extends StatelessWidget { | ||
LogsTable({ | ||
Key key, | ||
@required this.data, | ||
@required this.onItemSelected, | ||
@required this.selectionNotifier, | ||
@required this.searchMatchesNotifier, | ||
@required this.activeSearchMatchNotifier, | ||
}) : super(key: key); | ||
|
||
final List<LogData> data; | ||
final ItemCallback<LogData> onItemSelected; | ||
final ValueListenable<LogData> selectionNotifier; | ||
final ValueListenable<List<LogData>> searchMatchesNotifier; | ||
final ValueListenable<LogData> activeSearchMatchNotifier; | ||
|
||
final ColumnData<LogData> when = WhenColumn(); | ||
final ColumnData<LogData> kind = KindColumn(); | ||
final ColumnData<LogData> message = MessageColumn(); | ||
|
||
List<ColumnData<LogData>> get columns => [when, kind, message]; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return FlatTable<LogData>( | ||
columns: columns, | ||
data: data, | ||
autoScrollContent: true, | ||
keyFactory: (LogData data) => ValueKey<LogData>(data), | ||
onItemSelected: onItemSelected, | ||
selectionNotifier: selectionNotifier, | ||
sortColumn: when, | ||
secondarySortColumn: message, | ||
sortDirection: SortDirection.ascending, | ||
searchMatchesNotifier: searchMatchesNotifier, | ||
activeSearchMatchNotifier: activeSearchMatchNotifier, | ||
); | ||
} | ||
} |
107 changes: 107 additions & 0 deletions
107
packages/devtools_app/lib/src/screens/logging/_message_column.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// Copyright 2019 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. | ||
|
||
// @dart=2.9 | ||
|
||
import 'dart:convert'; | ||
|
||
import 'package:flutter/material.dart'; | ||
|
||
import '../../primitives/utils.dart'; | ||
import '../../shared/table.dart'; | ||
import '../../shared/table_data.dart'; | ||
import '../../shared/theme.dart'; | ||
import '../../ui/colors.dart'; | ||
import 'logging_controller.dart'; | ||
|
||
@visibleForTesting | ||
class MessageColumn extends ColumnData<LogData> | ||
implements ColumnRenderer<LogData> { | ||
MessageColumn() : super.wide('Message'); | ||
|
||
@override | ||
bool get supportsSorting => false; | ||
|
||
@override | ||
String getValue(LogData dataObject) => | ||
dataObject.summary ?? dataObject.details; | ||
|
||
@override | ||
int compare(LogData a, LogData b) { | ||
final String valueA = getValue(a); | ||
final String valueB = getValue(b); | ||
// Matches frame descriptions (e.g. '#12 11.4ms ') | ||
final regex = RegExp(r'#(\d+)\s+\d+.\d+ms\s*'); | ||
final valueAIsFrameLog = valueA.startsWith(regex); | ||
final valueBIsFrameLog = valueB.startsWith(regex); | ||
if (valueAIsFrameLog && valueBIsFrameLog) { | ||
final frameNumberA = regex.firstMatch(valueA)[1]; | ||
final frameNumberB = regex.firstMatch(valueB)[1]; | ||
return int.parse(frameNumberA).compareTo(int.parse(frameNumberB)); | ||
} else if (valueAIsFrameLog && !valueBIsFrameLog) { | ||
return -1; | ||
} else if (!valueAIsFrameLog && valueBIsFrameLog) { | ||
return 1; | ||
} | ||
return valueA.compareTo(valueB); | ||
} | ||
|
||
@override | ||
Widget build( | ||
BuildContext context, | ||
LogData data, { | ||
bool isRowSelected = false, | ||
VoidCallback onPressed, | ||
}) { | ||
TextStyle textStyle = Theme.of(context).fixedFontStyle; | ||
if (isRowSelected) { | ||
textStyle = textStyle.copyWith(color: defaultSelectionForegroundColor); | ||
} | ||
|
||
if (data.kind == 'flutter.frame') { | ||
const Color color = Color.fromARGB(0xff, 0x00, 0x91, 0xea); | ||
final Text text = Text( | ||
getDisplayValue(data), | ||
overflow: TextOverflow.ellipsis, | ||
style: textStyle, | ||
); | ||
|
||
double frameLength = 0.0; | ||
try { | ||
final int micros = jsonDecode(data.details)['elapsed']; | ||
frameLength = micros * 3.0 / 1000.0; | ||
} catch (e) { | ||
// ignore | ||
} | ||
|
||
return Row( | ||
children: <Widget>[ | ||
text, | ||
Flexible( | ||
child: Container( | ||
height: 12.0, | ||
width: frameLength, | ||
decoration: const BoxDecoration(color: color), | ||
), | ||
), | ||
], | ||
); | ||
} else if (data.kind == 'stdout') { | ||
return RichText( | ||
text: TextSpan( | ||
children: processAnsiTerminalCodes( | ||
// TODO(helin24): Recompute summary length considering ansi codes. | ||
// The current summary is generally the first 200 chars of details. | ||
getDisplayValue(data), | ||
textStyle, | ||
), | ||
), | ||
overflow: TextOverflow.ellipsis, | ||
maxLines: 1, | ||
); | ||
} else { | ||
return null; | ||
} | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
packages/devtools_app/lib/src/screens/logging/_when_column.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Copyright 2019 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. | ||
|
||
// @dart=2.9 | ||
|
||
import '../../shared/table_data.dart'; | ||
import '../../shared/utils.dart'; | ||
import 'logging_controller.dart'; | ||
|
||
class WhenColumn extends ColumnData<LogData> { | ||
WhenColumn() | ||
: super( | ||
'When', | ||
fixedWidthPx: scaleByFontFactor(120), | ||
); | ||
|
||
@override | ||
bool get supportsSorting => false; | ||
|
||
@override | ||
String getValue(LogData dataObject) => dataObject.timestamp == null | ||
? '' | ||
: timeFormat | ||
.format(DateTime.fromMillisecondsSinceEpoch(dataObject.timestamp)); | ||
} |
Oops, something went wrong.