normalize dialogs (#2073)
normalize dialogs
diff --git a/packages/devtools_app/lib/src/app.dart b/packages/devtools_app/lib/src/app.dart
index 0313d5e..1b893ec 100644
--- a/packages/devtools_app/lib/src/app.dart
+++ b/packages/devtools_app/lib/src/app.dart
@@ -12,6 +12,7 @@
import 'connect_screen.dart';
import 'debugger/debugger_controller.dart';
import 'debugger/debugger_screen.dart';
+import 'dialogs.dart';
import 'framework/framework_core.dart';
import 'globals.dart';
import 'initializer.dart';
@@ -334,29 +335,29 @@
class DevToolsAboutDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final textTheme = Theme.of(context).textTheme;
+ final theme = Theme.of(context);
- return AlertDialog(
- actions: [
- DialogCloseButton(),
- ],
+ return DevToolsDialog(
+ title: dialogTitleText(theme, 'About DevTools'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- ...headerInColumn(textTheme, 'About DevTools'),
_aboutDevTools(context),
const SizedBox(height: defaultSpacing),
- ...headerInColumn(textTheme, 'Feedback'),
+ ...dialogSubHeader(theme, 'Feedback'),
Wrap(
children: [
const Text('Encountered an issue? Let us know at '),
- _createFeedbackLink(context, textTheme),
+ _createFeedbackLink(context),
const Text('.')
],
),
],
),
+ actions: [
+ DialogCloseButton(),
+ ],
);
}
@@ -364,7 +365,7 @@
return const SelectableText('DevTools version ${devtools.version}');
}
- Widget _createFeedbackLink(BuildContext context, TextTheme textTheme) {
+ Widget _createFeedbackLink(BuildContext context) {
const urlPath = 'github.com/flutter/devtools/issues';
return InkWell(
@@ -387,15 +388,12 @@
Widget build(BuildContext context) {
final preferences = DevToolsApp.of(context).preferences;
- return AlertDialog(
- actions: [
- DialogCloseButton(),
- ],
+ return DevToolsDialog(
+ title: dialogTitleText(Theme.of(context), 'Settings'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- ...headerInColumn(Theme.of(context).textTheme, 'Settings'),
InkWell(
onTap: () {
preferences.toggleDarkModeTheme(!preferences.darkModeTheme.value);
@@ -419,6 +417,9 @@
),
],
),
+ actions: [
+ DialogCloseButton(),
+ ],
);
}
}
diff --git a/packages/devtools_app/lib/src/common_widgets.dart b/packages/devtools_app/lib/src/common_widgets.dart
index 78cf724..d0620dd 100644
--- a/packages/devtools_app/lib/src/common_widgets.dart
+++ b/packages/devtools_app/lib/src/common_widgets.dart
@@ -24,20 +24,6 @@
const areaPaneHeaderHeight = 36.0;
-List<Widget> headerInColumn(TextTheme textTheme, String title) {
- return [
- Text(title, style: textTheme.headline6),
- const PaddedDivider(padding: EdgeInsets.only(bottom: denseRowSpacing)),
- ];
-}
-
-List<Widget> subHeaderInColumn(TextTheme textTheme, String title) {
- return [
- Text(title, style: textTheme.subtitle2),
- const PaddedDivider(padding: EdgeInsets.only(bottom: denseRowSpacing)),
- ];
-}
-
/// Convenience [Divider] with [Padding] that provides a good divider in forms.
class PaddedDivider extends StatelessWidget {
const PaddedDivider({
@@ -498,19 +484,6 @@
);
}
-/// A FlatButton used to close a containing dialog.
-class DialogCloseButton extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- return FlatButton(
- onPressed: () {
- Navigator.of(context, rootNavigator: true).pop('dialog');
- },
- child: const Text('CLOSE'),
- );
- }
-}
-
/// Toggle button for use as a child of a [ToggleButtons] widget.
class ToggleButton extends StatelessWidget {
const ToggleButton({
diff --git a/packages/devtools_app/lib/src/device_dialog.dart b/packages/devtools_app/lib/src/device_dialog.dart
index 0a3a133..200e792 100644
--- a/packages/devtools_app/lib/src/device_dialog.dart
+++ b/packages/devtools_app/lib/src/device_dialog.dart
@@ -10,6 +10,7 @@
import 'auto_dispose_mixin.dart';
import 'common_widgets.dart';
import 'connected_app.dart';
+import 'dialogs.dart';
import 'globals.dart';
import 'info/info_controller.dart';
import 'table.dart';
@@ -58,16 +59,12 @@
'${flutterVersion.engineRevision}';
}
- return AlertDialog(
- actions: [
- if (connectedApp.isRunningOnDartVM) _ViewVMFlagsButton(),
- DialogCloseButton(),
- ],
+ return DevToolsDialog(
+ title: dialogTitleText(theme, 'Device Info'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- ...headerInColumn(theme.textTheme, 'Device Info'),
for (var name in items.keys)
Padding(
padding: const EdgeInsets.only(bottom: denseRowSpacing),
@@ -80,6 +77,10 @@
),
],
),
+ actions: [
+ if (connectedApp.isRunningOnDartVM) _ViewVMFlagsButton(),
+ DialogCloseButton(),
+ ],
);
}
}
@@ -154,36 +155,31 @@
@override
Widget build(BuildContext context) {
- final textTheme = Theme.of(context).textTheme;
+ final theme = Theme.of(context);
- return AlertDialog(
- actions: [
- DialogCloseButton(),
- ],
+ return DevToolsDialog(
+ title: Row(
+ children: [
+ dialogTitleText(theme, 'VM Flags'),
+ const Expanded(child: SizedBox(width: denseSpacing)),
+ Container(
+ width: defaultSearchTextWidth,
+ height: defaultSearchTextHeight,
+ child: TextField(
+ controller: filterController,
+ decoration: const InputDecoration(
+ isDense: true,
+ border: OutlineInputBorder(),
+ labelText: 'Filter',
+ ),
+ ),
+ ),
+ ],
+ ),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Row(
- children: [
- Text('VM Flags', style: textTheme.headline6),
- const Expanded(child: SizedBox(width: denseSpacing)),
- Container(
- width: defaultSearchTextWidth,
- height: defaultSearchTextHeight,
- child: TextField(
- controller: filterController,
- decoration: const InputDecoration(
- isDense: true,
- border: OutlineInputBorder(),
- labelText: 'Filter',
- ),
- ),
- ),
- ],
- ),
- const PaddedDivider(
- padding: EdgeInsets.only(bottom: denseRowSpacing)),
SizedBox(
width: 875,
height: 375,
@@ -191,6 +187,9 @@
),
],
),
+ actions: [
+ DialogCloseButton(),
+ ],
);
}
diff --git a/packages/devtools_app/lib/src/dialogs.dart b/packages/devtools_app/lib/src/dialogs.dart
new file mode 100644
index 0000000..384c791
--- /dev/null
+++ b/packages/devtools_app/lib/src/dialogs.dart
@@ -0,0 +1,102 @@
+// Copyright 2020 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/material.dart';
+
+import 'common_widgets.dart';
+import 'theme.dart';
+
+const _dialogDefaultContext = 'dialog';
+
+Text dialogTitleText(ThemeData theme, String text) {
+ return Text(text, style: theme.textTheme.headline6);
+}
+
+List<Widget> dialogSubHeader(ThemeData theme, String titleText) {
+ return [
+ Text(titleText, style: theme.textTheme.subtitle1),
+ const PaddedDivider(padding: EdgeInsets.only(bottom: denseRowSpacing)),
+ ];
+}
+
+/// A standardized dialog for use in DevTools.
+///
+/// It normalizes dialog layout, spacing, and look and feel.
+class DevToolsDialog extends StatelessWidget {
+ const DevToolsDialog({
+ @required this.title,
+ @required this.content,
+ this.actions,
+ });
+
+ static const contentPadding = 24.0;
+
+ final Widget title;
+ final Widget content;
+ final List<Widget> actions;
+
+ @override
+ Widget build(BuildContext context) {
+ return AlertDialog(
+ title: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ title,
+ const PaddedDivider(
+ padding: EdgeInsets.only(bottom: denseRowSpacing),
+ ),
+ ],
+ ),
+ contentPadding: const EdgeInsets.fromLTRB(
+ contentPadding, 0, contentPadding, contentPadding),
+ content: content,
+ actions: actions,
+ );
+ }
+}
+
+/// A FlatButton used to close a containing dialog (Close).
+class DialogCloseButton extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return FlatButton(
+ onPressed: () {
+ Navigator.of(context, rootNavigator: true).pop('dialog');
+ },
+ child: const Text('CLOSE'),
+ );
+ }
+}
+
+/// A FlatButton used to close a containing dialog (Cancel).
+class DialogCancelButton extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return FlatButton(
+ onPressed: () {
+ Navigator.of(context).pop(_dialogDefaultContext);
+ },
+ child: const Text('CANCEL'),
+ );
+ }
+}
+
+/// A FlatButton used to close a containing dialog (OK).
+class DialogOkButton extends StatelessWidget {
+ const DialogOkButton(this.onOk) : super();
+
+ final Function onOk;
+
+ @override
+ Widget build(BuildContext context) {
+ return FlatButton(
+ onPressed: () {
+ if (onOk != null) onOk();
+ Navigator.of(context).pop(_dialogDefaultContext);
+ },
+ child: const Text('OK'),
+ );
+ }
+}
diff --git a/packages/devtools_app/lib/src/memory/memory_filter.dart b/packages/devtools_app/lib/src/memory/memory_filter.dart
index 8dc5bcb..4a9699b 100644
--- a/packages/devtools_app/lib/src/memory/memory_filter.dart
+++ b/packages/devtools_app/lib/src/memory/memory_filter.dart
@@ -6,9 +6,8 @@
import 'package:vm_service/vm_service.dart';
import '../auto_dispose_mixin.dart';
-import '../common_widgets.dart';
+import '../dialogs.dart';
import '../flutter_widgets/linked_scroll_controller.dart';
-import '../ui/dialog.dart';
import '../ui/utils.dart';
import 'memory_controller.dart';
import 'memory_snapshot_models.dart';
@@ -260,7 +259,7 @@
Widget okCancelButtons() {
return Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ mainAxisAlignment: MainAxisAlignment.end,
children: [
DialogOkButton(
() {
@@ -312,10 +311,9 @@
// - one list of libraries with at least 5 entries
// - one row of buttons Ok/Cancel
// For very tall app keep the dialog at a reasonable height w/o too much vertical whitespace.
- // The listbox area is the area that grows to accomodate the list of known libraries.
+ // The listbox area is the area that grows to accommodate the list of known libraries.
+ // TODO(devoncarew): Convert to a DevToolsDialog.
return Dialog(
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(defaultDialogRadius)),
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Container(
diff --git a/packages/devtools_app/lib/src/timeline/timeline_screen.dart b/packages/devtools_app/lib/src/timeline/timeline_screen.dart
index d7f5081..e180242 100644
--- a/packages/devtools_app/lib/src/timeline/timeline_screen.dart
+++ b/packages/devtools_app/lib/src/timeline/timeline_screen.dart
@@ -12,6 +12,7 @@
import '../banner_messages.dart';
import '../common_widgets.dart';
import '../config_specific/import_export/import_export.dart';
+import '../dialogs.dart';
import '../globals.dart';
import '../notifications.dart';
import '../octicons.dart';
@@ -354,22 +355,24 @@
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- return Dialog(
- child: Container(
+
+ return DevToolsDialog(
+ title: dialogTitleText(theme, 'Recorded Streams'),
+ content: Container(
width: dialogWidth,
- padding: const EdgeInsets.all(defaultSpacing),
child: Column(
- mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- ...headerInColumn(theme.textTheme, 'Recorded Streams'),
..._defaultRecordedStreams(theme),
const SizedBox(height: denseSpacing),
- ...subHeaderInColumn(theme.textTheme, 'Advanced'),
+ ...dialogSubHeader(theme, 'Advanced'),
..._advancedStreams(theme),
],
),
),
+ actions: [
+ DialogCloseButton(),
+ ],
);
}
diff --git a/packages/devtools_app/lib/src/ui/dialog.dart b/packages/devtools_app/lib/src/ui/dialog.dart
deleted file mode 100644
index d2ef1a4..0000000
--- a/packages/devtools_app/lib/src/ui/dialog.dart
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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.
-
-import 'package:flutter/material.dart';
-
-const dialogDefault = 'dialog';
-
-/// A FlatButton used to close a containing dialog - Cancel.
-class DialogCancelButton extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- return FlatButton(
- onPressed: () {
- Navigator.of(context).pop(dialogDefault);
- },
- child: const Text('Cancel'),
- );
- }
-}
-
-/// A FlatButton used to close a containing dialog - OK.
-class DialogOkButton extends StatelessWidget {
- const DialogOkButton(this.onOk) : super();
-
- final Function onOk;
-
- @override
- Widget build(BuildContext context) {
- return FlatButton(
- onPressed: () {
- if (onOk != null) onOk();
- Navigator.of(context).pop(dialogDefault);
- },
- child: const Text('OK'),
- );
- }
-}