Skip to content

Commit 513884f

Browse files
Add a warning to stop launching on pub for DevTools version 2.8.0 (flutter#3464)
1 parent 3f21103 commit 513884f

10 files changed

Lines changed: 208 additions & 40 deletions

File tree

packages/devtools_app/lib/src/app.dart

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import 'screen.dart';
4747
import 'snapshot_screen.dart';
4848
import 'theme.dart';
4949
import 'ui/service_extension_widgets.dart';
50+
import 'utils.dart';
5051
import 'vm_developer/vm_developer_tools_controller.dart';
5152
import 'vm_developer/vm_developer_tools_screen.dart';
5253

@@ -60,6 +61,13 @@ const showVmDeveloperMode = false;
6061
/// Whether this DevTools build is external.
6162
bool isExternalBuild = true;
6263

64+
// TODO(kenz): remove the pub warning code after devtools version 2.8.0 ships
65+
/// Whether DevTools should warn users to stop launching DevTools from Pub.
66+
///
67+
/// This flag will be turned on for the final release of DevTools on pub, but
68+
/// should remain off at HEAD.
69+
const showPubWarning = false;
70+
6371
/// Top-level configuration for the app.
6472
@immutable
6573
class DevToolsApp extends StatefulWidget {
@@ -487,7 +495,6 @@ class DevToolsAboutDialog extends StatelessWidget {
487495
@override
488496
Widget build(BuildContext context) {
489497
final theme = Theme.of(context);
490-
491498
return DevToolsDialog(
492499
title: dialogTitleText(theme, 'About DevTools'),
493500
content: Column(
@@ -496,6 +503,10 @@ class DevToolsAboutDialog extends StatelessWidget {
496503
children: [
497504
_aboutDevTools(context),
498505
const SizedBox(height: defaultSpacing),
506+
if (shouldShowPubWarning()) ...[
507+
const PubWarningText(),
508+
const SizedBox(height: defaultSpacing),
509+
],
499510
...dialogSubHeader(theme, 'Feedback'),
500511
Wrap(
501512
children: [

packages/devtools_app/lib/src/common_widgets.dart

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'dart:math';
88
import 'package:flutter/foundation.dart';
99
import 'package:flutter/material.dart';
1010

11+
import 'globals.dart';
1112
import 'scaffold.dart';
1213
import 'theme.dart';
1314
import 'ui/icons.dart';
@@ -1531,3 +1532,40 @@ class CheckboxSetting extends StatelessWidget {
15311532
return content;
15321533
}
15331534
}
1535+
1536+
class PubWarningText extends StatelessWidget {
1537+
const PubWarningText({Key key}) : super(key: key);
1538+
1539+
@override
1540+
Widget build(BuildContext context) {
1541+
final theme = Theme.of(context);
1542+
final isFlutterApp = serviceManager.connectedApp.isFlutterAppNow;
1543+
final sdkName = isFlutterApp ? 'Flutter' : 'Dart';
1544+
final minSdkVersion = isFlutterApp ? '2.8.0' : '2.15.0';
1545+
return SelectableText.rich(
1546+
TextSpan(
1547+
text: 'Warning: you should no longer be launching DevTools from'
1548+
' pub.\n\n',
1549+
style: theme.subtleTextStyle
1550+
.copyWith(color: theme.colorScheme.errorTextColor),
1551+
children: [
1552+
TextSpan(
1553+
text: 'DevTools version 2.8.0 will be the last version to '
1554+
'be shipped on pub. As of $sdkName\nversion >= '
1555+
'$minSdkVersion, DevTools should be launched by running '
1556+
'the ',
1557+
style: theme.subtleTextStyle,
1558+
),
1559+
TextSpan(
1560+
text: '`dart devtools`',
1561+
style: theme.subtleFixedFontStyle,
1562+
),
1563+
TextSpan(
1564+
text: '\ncommand.',
1565+
style: theme.subtleTextStyle,
1566+
),
1567+
],
1568+
),
1569+
);
1570+
}
1571+
}

packages/devtools_app/lib/src/initializer.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,7 @@ class _InitializerState extends State<Initializer>
150150
final theme = Theme.of(context);
151151
currentDisconnectedOverlay = OverlayEntry(
152152
builder: (context) => Container(
153-
// TODO(dantup): Change this to a theme colour and ensure it works in both dart/light themes
154-
color: const Color.fromRGBO(128, 128, 128, 0.5),
153+
color: theme.colorScheme.overlayShadowColor,
155154
child: Center(
156155
child: Column(
157156
children: [

packages/devtools_app/lib/src/performance/performance_screen.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import '../screen.dart';
2121
import '../service_extensions.dart';
2222
import '../split.dart';
2323
import '../theme.dart';
24-
import '../ui/colors.dart';
2524
import '../ui/icons.dart';
2625
import '../ui/service_extension_widgets.dart';
2726
import '../ui/vm_flag_widgets.dart';
@@ -367,7 +366,8 @@ class EnhanceTracingButton extends StatelessWidget {
367366

368367
@override
369368
Widget build(BuildContext context) {
370-
final textStyle = Theme.of(context).subtleTextStyle;
369+
final theme = Theme.of(context);
370+
final textStyle = theme.subtleTextStyle;
371371
return ServiceExtensionCheckboxGroupButton(
372372
title: 'Enhance Tracing',
373373
icon: Icons.auto_awesome,
@@ -387,7 +387,8 @@ class EnhanceTracingButton extends StatelessWidget {
387387
children: [
388388
TextSpan(
389389
text: 'frame times may be negatively affected',
390-
style: textStyle.copyWith(color: rasterJankColor),
390+
style:
391+
textStyle.copyWith(color: theme.colorScheme.errorTextColor),
391392
),
392393
TextSpan(
393394
text: '.',

packages/devtools_app/lib/src/scaffold.dart

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,49 @@ class DevToolsScaffoldState extends State<DevToolsScaffold>
137137
frameworkController.onShowPageId.listen(_showPageById);
138138

139139
_initTitle();
140+
_maybeShowPubWarning();
141+
}
142+
143+
bool _pubWarningShown = false;
144+
145+
// TODO(kenz): remove the pub warning code after devtools version 2.8.0 ships
146+
void _maybeShowPubWarning() {
147+
if (!_pubWarningShown) {
148+
serviceManager.onConnectionAvailable?.listen((event) {
149+
if (shouldShowPubWarning()) {
150+
final colorScheme = Theme.of(context).colorScheme;
151+
OverlayEntry _entry;
152+
Overlay.of(context).insert(
153+
_entry = OverlayEntry(
154+
maintainState: true,
155+
builder: (context) {
156+
return Material(
157+
color: colorScheme.overlayShadowColor,
158+
child: Center(
159+
child: Container(
160+
padding: const EdgeInsets.all(defaultSpacing),
161+
color: colorScheme.overlayBackgroundColor,
162+
child: Column(
163+
mainAxisSize: MainAxisSize.min,
164+
children: [
165+
const PubWarningText(),
166+
const SizedBox(height: defaultSpacing),
167+
ElevatedButton(
168+
child: const Text('Got it'),
169+
onPressed: () => _entry.remove(),
170+
),
171+
],
172+
),
173+
),
174+
),
175+
);
176+
},
177+
),
178+
);
179+
_pubWarningShown = true;
180+
}
181+
});
182+
}
140183
}
141184

142185
@override

packages/devtools_app/lib/src/theme.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,13 @@ extension DevToolsColorScheme on ColorScheme {
234234
Color get contrastForeground =>
235235
isLight ? Colors.black : _contrastForegroundWhite;
236236

237+
Color get overlayShadowColor => const Color.fromRGBO(0, 0, 0, 0.5);
238+
239+
Color get overlayBackgroundColor =>
240+
isLight ? Colors.white : const Color(0xFF424242);
241+
242+
Color get errorTextColor => const Color(0xFFC3595A);
243+
237244
Color get toggleButtonsTitle =>
238245
isLight ? const Color(0xFF464646) : const Color(0xFFAEAEB1);
239246

packages/devtools_app/lib/src/utils.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ import 'package:flutter/widgets.dart';
1616
import 'package:intl/intl.dart';
1717
import 'package:vm_service/vm_service.dart';
1818

19+
import 'app.dart';
1920
import 'config_specific/logger/logger.dart' as logger;
2021
import 'globals.dart';
2122
import 'notifications.dart';
23+
import 'version.dart';
2224

2325
bool isPrivate(String member) => member.startsWith('_');
2426

@@ -1425,3 +1427,12 @@ const connectToNewAppText = 'Connect to a new app';
14251427
/// Exception thrown when a request to process data has been cancelled in
14261428
/// favor of a new request.
14271429
class ProcessCancelledException implements Exception {}
1430+
1431+
bool shouldShowPubWarning() =>
1432+
showPubWarning &&
1433+
(serviceManager.connectedApp?.isFlutterAppNow != null &&
1434+
serviceManager.connectedApp.flutterVersionNow >=
1435+
SemanticVersion(major: 2, minor: 8) ||
1436+
(serviceManager.vm != null &&
1437+
SemanticVersion.parse(serviceManager.vm.version) >=
1438+
SemanticVersion(major: 2, minor: 15)));

packages/devtools_app/lib/src/version.dart

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,12 @@ class FlutterVersion extends SemanticVersion {
1616
@required this.engineRevision,
1717
@required this.dartSdkVersion,
1818
}) {
19-
// Flutter versions are expected in the format '2.3.1-16.1-pre', so we split
20-
// on the dash char to separate the main semantic version from the pre
21-
// release version.
22-
final splitOnDash = version.split('-');
23-
assert(splitOnDash.length <= 2);
24-
25-
final semVersion = splitOnDash.first;
26-
final _versionParts = semVersion.split('.');
27-
major =
28-
_versionParts.isNotEmpty ? int.tryParse(_versionParts.first) ?? 0 : 0;
29-
minor = _versionParts.length > 1 ? int.tryParse(_versionParts[1]) ?? 0 : 0;
30-
patch = _versionParts.length > 2 ? int.tryParse(_versionParts[2]) ?? 0 : 0;
31-
32-
if (splitOnDash.length == 2) {
33-
final preRelease = splitOnDash.last;
34-
final preReleaseParts = preRelease
35-
.split('.')
36-
.map((part) => RegExp(r'\d+').stringMatch(part) ?? '')
37-
.toList()
38-
..removeWhere((part) => part.isEmpty);
39-
preReleaseMajor = preReleaseParts.isNotEmpty
40-
? int.tryParse(preReleaseParts.first) ?? 0
41-
: 0;
42-
preReleaseMinor = preReleaseParts.length > 1
43-
? int.tryParse(preReleaseParts[1]) ?? 0
44-
: 0;
45-
}
19+
final semVer = SemanticVersion.parse(version);
20+
major = semVer.major;
21+
minor = semVer.minor;
22+
patch = semVer.patch;
23+
preReleaseMajor = semVer.preReleaseMajor;
24+
preReleaseMinor = semVer.preReleaseMinor;
4625
}
4726

4827
factory FlutterVersion.parse(Map<String, dynamic> json) {
@@ -53,7 +32,7 @@ class FlutterVersion extends SemanticVersion {
5332
frameworkRevision: json['frameworkRevisionShort'],
5433
frameworkCommitDate: json['frameworkCommitDate'],
5534
engineRevision: json['engineRevisionShort'],
56-
dartSdkVersion: json['dartSdkVersion'],
35+
dartSdkVersion: _parseDartVersion(json['dartSdkVersion']),
5736
);
5837
}
5938

@@ -69,7 +48,7 @@ class FlutterVersion extends SemanticVersion {
6948

7049
final String engineRevision;
7150

72-
final String dartSdkVersion;
51+
final SemanticVersion dartSdkVersion;
7352

7453
String get flutterVersionSummary => [
7554
if (version != 'unknown') version,
@@ -103,6 +82,19 @@ class FlutterVersion extends SemanticVersion {
10382
engineRevision,
10483
dartSdkVersion,
10584
);
85+
86+
static SemanticVersion _parseDartVersion(String versionString) {
87+
if (versionString == null) return null;
88+
89+
// Example Dart version string: "2.15.0 (build 2.15.0-178.1.beta)"
90+
const prefix = '(build ';
91+
final startIndex = versionString.indexOf(prefix) + prefix.length;
92+
final rawVersion = versionString.substring(
93+
startIndex,
94+
versionString.length - 1,
95+
);
96+
return SemanticVersion.parse(rawVersion);
97+
}
10698
}
10799

108100
class SemanticVersion with CompareMixin {
@@ -114,6 +106,54 @@ class SemanticVersion with CompareMixin {
114106
this.preReleaseMinor,
115107
});
116108

109+
factory SemanticVersion.parse(String versionString) {
110+
// [versionString] is expected to be of the form for VM.version, Dart, and
111+
// Flutter, respectively:
112+
// 2.15.0-233.0.dev (dev) (Mon Oct 18 14:06:26 2021 -0700) on "ios_x64"
113+
// 2.15.0-178.1.beta
114+
// 2.6.0-12.0.pre.443
115+
//
116+
// So split on the spaces to the version, and then on the dash char to
117+
// separate the main semantic version from the pre release version.
118+
final splitOnSpaces = versionString.split(' ');
119+
final version = splitOnSpaces.first;
120+
final splitOnDash = version.split('-');
121+
assert(splitOnDash.length <= 2, 'version: $version');
122+
123+
final semVersion = splitOnDash.first;
124+
final _versionParts = semVersion.split('.');
125+
final major =
126+
_versionParts.isNotEmpty ? int.tryParse(_versionParts.first) ?? 0 : 0;
127+
final minor =
128+
_versionParts.length > 1 ? int.tryParse(_versionParts[1]) ?? 0 : 0;
129+
final patch =
130+
_versionParts.length > 2 ? int.tryParse(_versionParts[2]) ?? 0 : 0;
131+
132+
int preReleaseMajor;
133+
int preReleaseMinor;
134+
if (splitOnDash.length == 2) {
135+
final preRelease = splitOnDash.last;
136+
final preReleaseParts = preRelease
137+
.split('.')
138+
.map((part) => RegExp(r'\d+').stringMatch(part) ?? '')
139+
.toList()
140+
..removeWhere((part) => part.isEmpty);
141+
preReleaseMajor = preReleaseParts.isNotEmpty
142+
? int.tryParse(preReleaseParts.first) ?? 0
143+
: 0;
144+
preReleaseMinor = preReleaseParts.length > 1
145+
? int.tryParse(preReleaseParts[1]) ?? 0
146+
: 0;
147+
}
148+
return SemanticVersion(
149+
major: major,
150+
minor: minor,
151+
patch: patch,
152+
preReleaseMajor: preReleaseMajor,
153+
preReleaseMinor: preReleaseMinor,
154+
);
155+
}
156+
117157
int major;
118158

119159
int minor;
@@ -134,8 +174,8 @@ class SemanticVersion with CompareMixin {
134174
if (major == other.major &&
135175
minor == other.minor &&
136176
patch == other.patch &&
137-
preReleaseMajor == other.preReleaseMajor &&
138-
preReleaseMinor == other.preReleaseMinor) {
177+
(preReleaseMajor ?? 0) == (other.preReleaseMajor ?? 0) &&
178+
(preReleaseMinor ?? 0) == (other.preReleaseMinor ?? 0)) {
139179
return 0;
140180
}
141181
if (major > other.major ||
@@ -145,7 +185,7 @@ class SemanticVersion with CompareMixin {
145185
}
146186
if (major == other.major && minor == other.minor && patch == other.patch) {
147187
if (isPreRelease != other.isPreRelease) {
148-
return isPreRelease ? 1 : -1;
188+
return isPreRelease ? -1 : 1;
149189
}
150190
if (preReleaseMajor > other.preReleaseMajor ||
151191
(preReleaseMajor == other.preReleaseMajor &&

packages/devtools_app/test/version_test.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,21 @@ void main() {
121121
version.compareTo(SemanticVersion(major: 1, minor: 1, patch: 1)),
122122
equals(0),
123123
);
124+
expect(
125+
version.compareTo(SemanticVersion(
126+
major: 1,
127+
minor: 1,
128+
patch: 1,
129+
preReleaseMajor: 0,
130+
preReleaseMinor: 0,
131+
)),
132+
equals(0),
133+
);
124134

125135
expect(
126136
version.compareTo(
127137
SemanticVersion(major: 1, minor: 1, patch: 1, preReleaseMajor: 1)),
128-
equals(-1),
138+
equals(1),
129139
);
130140

131141
version = SemanticVersion(

0 commit comments

Comments
 (0)