Commit 5f38773e authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Screenshot improvements (#7800)

Add an "s" command to `flutter run` which takes a screenshot.
Make that comment turn off the slow mode banner.
parent 648f7063
......@@ -119,6 +119,14 @@ class WidgetsApp extends StatefulWidget {
/// Used by `showPerformanceOverlay` observatory extension.
static bool showPerformanceOverlayOverride = false;
/// If false, prevents the debug banner from being visible.
///
/// Used by `debugAllowBanner` observatory extension.
///
/// This is how `flutter run` turns off the banner when you take a screen shot
/// with "s".
static bool debugAllowBannerOverride = true;
@override
_WidgetsAppState createState() => new _WidgetsAppState();
}
......@@ -231,7 +239,7 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
);
}
assert(() {
if (config.debugShowCheckedModeBanner) {
if (config.debugShowCheckedModeBanner && WidgetsApp.debugAllowBannerOverride) {
result = new CheckedModeBanner(
child: result
);
......
......@@ -89,6 +89,17 @@ abstract class WidgetsBinding extends BindingBase implements GestureBinding, Ren
buildOwner.reassemble(renderViewElement);
}
);
registerBoolServiceExtension(
name: 'debugAllowBanner',
getter: () => WidgetsApp.debugAllowBannerOverride,
setter: (bool value) {
if (WidgetsApp.debugAllowBannerOverride == value)
return;
WidgetsApp.debugAllowBannerOverride = value;
buildOwner.reassemble(renderViewElement);
}
);
}
/// The [BuildOwner] in charge of executing the build pipeline for the
......
// Copyright 2017 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.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart';
class TestRoute<T> extends PageRoute<T> {
TestRoute({ this.child, RouteSettings settings }) : super(settings: settings);
final Widget child;
@override
Duration get transitionDuration => const Duration(milliseconds: 150);
@override
Color get barrierColor => null;
@override
bool get maintainState => false;
@override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> forwardAnimation) {
return child;
}
}
Future<Null> pumpApp(WidgetTester tester) async {
await tester.pumpWidget(new WidgetsApp(
color: const Color(0xFF333333),
onGenerateRoute: (RouteSettings settings) {
return new TestRoute<Null>(settings: settings, child: new Container());
},
));
}
void main() {
testWidgets('WidgetsApp control test', (WidgetTester tester) async {
await pumpApp(tester);
expect(find.byType(WidgetsApp), findsOneWidget);
expect(find.byType(Navigator), findsOneWidget);
expect(find.byType(PerformanceOverlay), findsNothing);
expect(find.byType(CheckedModeBanner), findsOneWidget);
});
testWidgets('showPerformanceOverlayOverride true', (WidgetTester tester) async {
expect(WidgetsApp.showPerformanceOverlayOverride, false);
WidgetsApp.showPerformanceOverlayOverride = true;
await pumpApp(tester);
expect(find.byType(WidgetsApp), findsOneWidget);
expect(find.byType(Navigator), findsOneWidget);
expect(find.byType(PerformanceOverlay), findsOneWidget);
expect(find.byType(CheckedModeBanner), findsOneWidget);
});
testWidgets('showPerformanceOverlayOverride false', (WidgetTester tester) async {
expect(WidgetsApp.showPerformanceOverlayOverride, true);
WidgetsApp.showPerformanceOverlayOverride = false;
await pumpApp(tester);
expect(find.byType(WidgetsApp), findsOneWidget);
expect(find.byType(Navigator), findsOneWidget);
expect(find.byType(PerformanceOverlay), findsNothing);
expect(find.byType(CheckedModeBanner), findsOneWidget);
});
testWidgets('debugAllowBannerOverride false', (WidgetTester tester) async {
expect(WidgetsApp.showPerformanceOverlayOverride, false);
expect(WidgetsApp.debugAllowBannerOverride, true);
WidgetsApp.debugAllowBannerOverride = false;
await pumpApp(tester);
expect(find.byType(WidgetsApp), findsOneWidget);
expect(find.byType(Navigator), findsOneWidget);
expect(find.byType(PerformanceOverlay), findsNothing);
expect(find.byType(CheckedModeBanner), findsNothing);
});
testWidgets('debugAllowBannerOverride true', (WidgetTester tester) async {
expect(WidgetsApp.showPerformanceOverlayOverride, false);
expect(WidgetsApp.debugAllowBannerOverride, false);
WidgetsApp.debugAllowBannerOverride = true;
await pumpApp(tester);
expect(find.byType(WidgetsApp), findsOneWidget);
expect(find.byType(Navigator), findsOneWidget);
expect(find.byType(PerformanceOverlay), findsNothing);
expect(find.byType(CheckedModeBanner), findsOneWidget);
});
}
......@@ -139,7 +139,7 @@ class ScreenshotCommand extends FlutterCommand {
}
Future<Null> showOutputFileInfo(File outputFile) async {
int sizeKB = (await outputFile.length()) ~/ 1000;
printStatus('Screenshot written to ${path.relative(outputFile.path)} (${sizeKB}kb).');
int sizeKB = (await outputFile.length()) ~/ 1024;
printStatus('Screenshot written to ${path.relative(outputFile.path)} (${sizeKB}kB).');
}
}
......@@ -7,17 +7,14 @@ import 'dart:async';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
import 'application_package.dart';
import 'base/file_system.dart';
import 'base/io.dart';
import 'base/os.dart';
import 'asset.dart';
import 'base/common.dart';
import 'base/file_system.dart';
import 'base/io.dart';
import 'base/logger.dart';
import 'base/os.dart';
import 'base/utils.dart';
import 'build_info.dart';
import 'dart/dependencies.dart';
import 'dart/package_map.dart';
......@@ -110,6 +107,24 @@ abstract class ResidentRunner {
await currentView.uiIsolate.flutterToggleDebugPaintSizeEnabled();
}
Future<Null> _screenshot() async {
File outputFile = getUniqueFile(fs.currentDirectory, 'flutter', 'png');
try {
if (vmService != null)
await vmService.vm.refreshViews();
if (isRunningDebug)
await currentView.uiIsolate.flutterDebugAllowBanner(false);
if (!await device.takeScreenshot(outputFile))
printError('Error taking screenshot.');
if (isRunningDebug)
await currentView.uiIsolate.flutterDebugAllowBanner(true);
int sizeKB = (await outputFile.length()) ~/ 1024;
printStatus('Screenshot written to ${path.relative(outputFile.path)} (${sizeKB}kB).');
} catch (error) {
printError('Error taking screenshot: $error');
}
}
void registerSignalHandlers() {
assert(stayResident);
ProcessSignal.SIGINT.watch().listen(_cleanUpAndExit);
......@@ -212,6 +227,11 @@ abstract class ResidentRunner {
return true;
await _debugToggleDebugPaintSizeEnabled();
return true;
} else if (lower == 's') {
if (!supportsServiceProtocol || !device.supportsScreenshot)
return true;
await _screenshot();
return true;
} else if (lower == 'q' || character == AnsiTerminal.KEY_F10) {
// F10, exit
await stop();
......@@ -309,9 +329,13 @@ abstract class ResidentRunner {
void printHelp({ @required bool details });
void printHelpDetails() {
printStatus('To dump the widget hierarchy of the app (debugDumpApp), press "w".');
printStatus('To dump the rendering tree of the app (debugDumpRenderTree), press "t".');
printStatus('To toggle the display of construction lines (debugPaintSizeEnabled), press "p".');
if (supportsServiceProtocol) {
printStatus('To dump the widget hierarchy of the app (debugDumpApp), press "w".');
printStatus('To dump the rendering tree of the app (debugDumpRenderTree), press "t".');
printStatus('To toggle the display of construction lines (debugPaintSizeEnabled), press "p".');
}
if (device.supportsScreenshot)
printStatus('To save a screenshot to flutter.png, press "s".');
}
/// Called when a signal has requested we exit.
......
......@@ -836,6 +836,10 @@ class Isolate extends ServiceObjectOwner {
return state;
}
Future<Null> flutterDebugAllowBanner(bool show) async {
await invokeFlutterExtensionRpcRaw('ext.flutter.debugAllowBanner', params: <String, dynamic>{ 'enabled': show });
}
// Reload related extension methods.
Future<Map<String, dynamic>> flutterReassemble() async {
return await invokeFlutterExtensionRpcRaw('ext.flutter.reassemble',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment