You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beam.apache.org by pa...@apache.org on 2021/10/25 18:51:14 UTC
[beam] branch master updated: Merge pull request #15783 from
[BEAM-13048] [Playground] Add shortcuts
This is an automated email from the ASF dual-hosted git repository.
pabloem pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git
The following commit(s) were added to refs/heads/master by this push:
new b52932c Merge pull request #15783 from [BEAM-13048] [Playground] Add shortcuts
b52932c is described below
commit b52932c34cb5862068336711b4297a08bb9e47ef
Author: Aydar Farrakhov <st...@gmail.com>
AuthorDate: Mon Oct 25 21:50:20 2021 +0300
Merge pull request #15783 from [BEAM-13048] [Playground] Add shortcuts
* [BEAM-13048]: add keyboard shortcuts to playground
* [BEAM-13048]: update shortcuts
* [BEAM-13048]: fix lint errors
---
playground/frontend/lib/config/theme.dart | 12 +++
playground/frontend/lib/constants/sizes.dart | 1 +
.../modules/shortcuts/components/shortcut_row.dart | 63 +++++++++++++
.../shortcuts/components/shortcuts_manager.dart} | 43 +++++----
.../shortcuts/components/shortcuts_modal.dart | 85 +++++++++++++++++
.../shortcuts/constants/global_shortcuts.dart | 103 +++++++++++++++++++++
.../shortcuts/models/shortcut.dart} | 33 +++----
.../pages/playground/components/more_actions.dart | 14 ++-
.../lib/pages/playground/playground_page.dart | 6 +-
.../pages/playground/states/playground_state.dart | 5 +
playground/frontend/lib/playground_app.dart | 17 ++--
11 files changed, 334 insertions(+), 48 deletions(-)
diff --git a/playground/frontend/lib/config/theme.dart b/playground/frontend/lib/config/theme.dart
index 9baeb58..a76336b 100644
--- a/playground/frontend/lib/config/theme.dart
+++ b/playground/frontend/lib/config/theme.dart
@@ -101,6 +101,16 @@ TabBarTheme createTabBarTheme(Color textColor, Color indicatorColor) {
);
}
+DialogTheme createDialogTheme(Color textColor) {
+ return DialogTheme(
+ titleTextStyle: TextStyle(
+ color: textColor,
+ fontSize: 32.0,
+ fontWeight: kBoldWeight,
+ ),
+ );
+}
+
final kLightTheme = ThemeData(
brightness: Brightness.light,
primaryColor: kLightPrimary,
@@ -111,6 +121,7 @@ final kLightTheme = ThemeData(
textButtonTheme: createTextButtonTheme(kLightText),
elevatedButtonTheme: createElevatedButtonTheme(kLightPrimary),
tabBarTheme: createTabBarTheme(kLightText, kLightPrimary),
+ dialogTheme: createDialogTheme(kLightText),
);
final kDarkTheme = ThemeData(
@@ -123,6 +134,7 @@ final kDarkTheme = ThemeData(
textButtonTheme: createTextButtonTheme(kDarkText),
elevatedButtonTheme: createElevatedButtonTheme(kDarkPrimary),
tabBarTheme: createTabBarTheme(kDarkText, kDarkPrimary),
+ dialogTheme: createDialogTheme(kDarkText),
);
class ThemeColors {
diff --git a/playground/frontend/lib/constants/sizes.dart b/playground/frontend/lib/constants/sizes.dart
index 66b8e16..a67eb78 100644
--- a/playground/frontend/lib/constants/sizes.dart
+++ b/playground/frontend/lib/constants/sizes.dart
@@ -30,6 +30,7 @@ const kIconButtonSplashRadius = 24.0;
const kFooterHeight = 32.0;
// border radius
+const double kSmBorderRadius = 4.0;
const double kBorderRadius = 8.0;
// elevation
diff --git a/playground/frontend/lib/modules/shortcuts/components/shortcut_row.dart b/playground/frontend/lib/modules/shortcuts/components/shortcut_row.dart
new file mode 100644
index 0000000..27ddbe6
--- /dev/null
+++ b/playground/frontend/lib/modules/shortcuts/components/shortcut_row.dart
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:playground/constants/sizes.dart';
+import 'package:playground/modules/shortcuts/models/shortcut.dart';
+
+const kMetaKeyName = 'CMD/CTRL';
+const kShortcutKeyJoinSymbol = ' + ';
+
+class ShortcutRow extends StatelessWidget {
+ final Shortcut shortcut;
+
+ const ShortcutRow({Key? key, required this.shortcut}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ final primaryColor = Theme.of(context).primaryColor;
+ // wrap with row to shrink container to child size
+ return Row(
+ children: [
+ Container(
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: primaryColor,
+ ),
+ borderRadius: BorderRadius.circular(kSmBorderRadius),
+ ),
+ padding: const EdgeInsets.all(kMdSpacing),
+ child: Text(
+ shortcut.shortcuts.keys
+ .map((e) => getKeyDisplayName(e))
+ .join(kShortcutKeyJoinSymbol),
+ style: TextStyle(color: primaryColor),
+ ),
+ ),
+ ],
+ );
+ }
+
+ String getKeyDisplayName(LogicalKeyboardKey e) {
+ if (e.keyId == LogicalKeyboardKey.meta.keyId) {
+ return kMetaKeyName;
+ }
+ return e.keyLabel;
+ }
+}
diff --git a/playground/frontend/lib/playground_app.dart b/playground/frontend/lib/modules/shortcuts/components/shortcuts_manager.dart
similarity index 53%
copy from playground/frontend/lib/playground_app.dart
copy to playground/frontend/lib/modules/shortcuts/components/shortcuts_manager.dart
index 8ce11d1..32d3ce2 100644
--- a/playground/frontend/lib/playground_app.dart
+++ b/playground/frontend/lib/modules/shortcuts/components/shortcuts_manager.dart
@@ -17,28 +17,35 @@
*/
import 'package:flutter/material.dart';
-import 'package:playground/config/theme.dart';
-import 'package:playground/pages/playground/playground_page.dart';
-import 'package:provider/provider.dart';
+import 'package:playground/modules/shortcuts/models/shortcut.dart';
-class PlaygroundApp extends StatelessWidget {
- const PlaygroundApp({Key? key}) : super(key: key);
+class ShortcutsManager extends StatelessWidget {
+ final Widget child;
+ final List<Shortcut> shortcuts;
+
+ const ShortcutsManager({
+ Key? key,
+ required this.child,
+ required this.shortcuts,
+ }) : super(key: key);
@override
Widget build(BuildContext context) {
- return ChangeNotifierProvider(
- create: (context) => ThemeProvider(),
- builder: (context, _) {
- final themeProvider = Provider.of<ThemeProvider>(context);
- return MaterialApp(
- title: 'Apache Beam Playground',
- themeMode: themeProvider.themeMode,
- theme: kLightTheme,
- darkTheme: kDarkTheme,
- home: const PlaygroundPage(),
- debugShowCheckedModeBanner: false,
- );
- },
+ return FocusableActionDetector(
+ autofocus: true,
+ shortcuts: _shortcutsMap,
+ actions: _getActions(context),
+ child: child,
);
}
+
+ Map<LogicalKeySet, Intent> get _shortcutsMap => {
+ for (var shortcut in shortcuts)
+ shortcut.shortcuts: shortcut.actionIntent
+ };
+
+ Map<Type, Action<Intent>> _getActions(BuildContext context) => {
+ for (var shortcut in shortcuts)
+ shortcut.actionIntent.runtimeType: shortcut.createAction(context)
+ };
}
diff --git a/playground/frontend/lib/modules/shortcuts/components/shortcuts_modal.dart b/playground/frontend/lib/modules/shortcuts/components/shortcuts_modal.dart
new file mode 100644
index 0000000..d2d048e
--- /dev/null
+++ b/playground/frontend/lib/modules/shortcuts/components/shortcuts_modal.dart
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import 'package:flutter/material.dart';
+import 'package:playground/constants/font_weight.dart';
+import 'package:playground/constants/sizes.dart';
+import 'package:playground/modules/shortcuts/components/shortcut_row.dart';
+import 'package:playground/modules/shortcuts/constants/global_shortcuts.dart';
+
+const kCloseText = 'CLOSE';
+const kButtonBorderRadius = 24.0;
+const kButtonWidth = 120.0;
+const kButtonHeight = 40.0;
+const kDialogPadding = 40.0;
+
+class ShortcutsModal extends StatelessWidget {
+ const ShortcutsModal({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return AlertDialog(
+ title: const Text('Shortcuts'),
+ titlePadding: const EdgeInsets.only(
+ top: kDialogPadding,
+ left: kDialogPadding,
+ ),
+ contentPadding: const EdgeInsets.all(kDialogPadding),
+ actionsPadding: const EdgeInsets.only(
+ bottom: kDialogPadding,
+ right: kDialogPadding,
+ ),
+ content: Wrap(
+ crossAxisAlignment: WrapCrossAlignment.start,
+ runSpacing: kLgSpacing,
+ children: [
+ ...globalShortcuts.map(
+ (shortcut) => Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Expanded(child: ShortcutRow(shortcut: shortcut)),
+ Expanded(
+ flex: 3,
+ child: Text(
+ shortcut.name,
+ style: const TextStyle(fontWeight: kBoldWeight),
+ ),
+ ),
+ ],
+ ),
+ )
+ ],
+ ),
+ actions: [
+ ElevatedButton(
+ child: const Text(kCloseText),
+ style: ButtonStyle(
+ elevation: MaterialStateProperty.all<double>(0.0),
+ fixedSize: MaterialStateProperty.all<Size>(
+ const Size(kButtonWidth, kButtonHeight),
+ ),
+ shape: MaterialStateProperty.all<StadiumBorder>(
+ const StadiumBorder(),
+ ),
+ ),
+ onPressed: () => Navigator.of(context).pop(),
+ ),
+ ],
+ );
+ }
+}
diff --git a/playground/frontend/lib/modules/shortcuts/constants/global_shortcuts.dart b/playground/frontend/lib/modules/shortcuts/constants/global_shortcuts.dart
new file mode 100644
index 0000000..38e35de
--- /dev/null
+++ b/playground/frontend/lib/modules/shortcuts/constants/global_shortcuts.dart
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:playground/modules/shortcuts/models/shortcut.dart';
+import 'package:playground/pages/playground/states/playground_state.dart';
+import 'package:provider/provider.dart';
+import 'package:url_launcher/url_launcher.dart';
+
+const kRunText = 'Run';
+const kResetText = 'Reset';
+const kClearOutputText = 'Clear Output';
+const kNewExampleText = 'New Example';
+
+class ResetIntent extends Intent {
+ const ResetIntent();
+}
+
+class RunIntent extends Intent {
+ const RunIntent();
+}
+
+class ClearOutputIntent extends Intent {
+ const ClearOutputIntent();
+}
+
+class NewExampleIntent extends Intent {
+ const NewExampleIntent();
+}
+
+final List<Shortcut> globalShortcuts = [
+ Shortcut(
+ shortcuts: LogicalKeySet(
+ LogicalKeyboardKey.meta,
+ LogicalKeyboardKey.enter,
+ ),
+ actionIntent: const RunIntent(),
+ name: kRunText,
+ createAction: (BuildContext context) => CallbackAction(
+ onInvoke: (_) => Provider.of<PlaygroundState>(
+ context,
+ listen: false,
+ ).runCode(),
+ ),
+ ),
+ Shortcut(
+ shortcuts: LogicalKeySet(
+ LogicalKeyboardKey.meta,
+ LogicalKeyboardKey.shift,
+ LogicalKeyboardKey.keyR,
+ ),
+ actionIntent: const ResetIntent(),
+ name: kResetText,
+ createAction: (BuildContext context) => CallbackAction(
+ onInvoke: (_) => Provider.of<PlaygroundState>(
+ context,
+ listen: false,
+ ).reset(),
+ ),
+ ),
+ Shortcut(
+ shortcuts: LogicalKeySet(
+ LogicalKeyboardKey.meta,
+ LogicalKeyboardKey.shift,
+ LogicalKeyboardKey.keyC,
+ ),
+ actionIntent: const ClearOutputIntent(),
+ name: kClearOutputText,
+ createAction: (BuildContext context) => CallbackAction(
+ onInvoke: (_) => Provider.of<PlaygroundState>(
+ context,
+ listen: false,
+ ).clearOutput(),
+ ),
+ ),
+ Shortcut(
+ shortcuts: LogicalKeySet(
+ LogicalKeyboardKey.meta,
+ LogicalKeyboardKey.keyM,
+ ),
+ actionIntent: const NewExampleIntent(),
+ name: kNewExampleText,
+ createAction: (_) => CallbackAction(
+ onInvoke: (_) => launch('/'),
+ ),
+ ),
+];
diff --git a/playground/frontend/lib/constants/sizes.dart b/playground/frontend/lib/modules/shortcuts/models/shortcut.dart
similarity index 62%
copy from playground/frontend/lib/constants/sizes.dart
copy to playground/frontend/lib/modules/shortcuts/models/shortcut.dart
index 66b8e16..15301a8 100644
--- a/playground/frontend/lib/constants/sizes.dart
+++ b/playground/frontend/lib/modules/shortcuts/models/shortcut.dart
@@ -16,25 +16,18 @@
* limitations under the License.
*/
-// spacings
-const double kZeroSpacing = 0.0;
-const double kSmSpacing = 4.0;
-const double kMdSpacing = 8.0;
-const double kLgSpacing = 16.0;
+import 'package:flutter/material.dart';
-// sizes
-const kHeaderButtonHeight = 46.0;
-const kRunButtonWidth = 150.0;
-const kRunButtonHeight = 40.0;
-const kIconButtonSplashRadius = 24.0;
-const kFooterHeight = 32.0;
+class Shortcut {
+ final String name;
+ final LogicalKeySet shortcuts;
+ final Intent actionIntent;
+ final Function createAction;
-// border radius
-const double kBorderRadius = 8.0;
-
-// elevation
-const int kElevation = 1;
-
-// icon sizes
-const double kIconSizeSm = 16.0;
-const double kIconSizeMd = 24.0;
+ Shortcut({
+ required this.name,
+ required this.shortcuts,
+ required this.actionIntent,
+ required this.createAction,
+ });
+}
diff --git a/playground/frontend/lib/pages/playground/components/more_actions.dart b/playground/frontend/lib/pages/playground/components/more_actions.dart
index cd590ca..23ee0bf 100644
--- a/playground/frontend/lib/pages/playground/components/more_actions.dart
+++ b/playground/frontend/lib/pages/playground/components/more_actions.dart
@@ -21,6 +21,7 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:playground/config/theme.dart';
import 'package:playground/constants/assets.dart';
+import 'package:playground/modules/shortcuts/components/shortcuts_modal.dart';
import 'package:url_launcher/url_launcher.dart';
enum HeaderAction {
@@ -50,10 +51,15 @@ const kBeamWebsiteLink = "https://beam.apache.org/";
const kAboutBeamText = "About Apache Beam";
-class MoreActions extends StatelessWidget {
+class MoreActions extends StatefulWidget {
const MoreActions({Key? key}) : super(key: key);
@override
+ State<MoreActions> createState() => _MoreActionsState();
+}
+
+class _MoreActionsState extends State<MoreActions> {
+ @override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
@@ -69,6 +75,12 @@ class MoreActions extends StatelessWidget {
child: ListTile(
leading: SvgPicture.asset(kShortcutsIconAsset),
title: const Text(kShortcutsText),
+ onTap: () => {
+ showDialog<void>(
+ context: context,
+ builder: (BuildContext context) => const ShortcutsModal(),
+ )
+ },
),
),
PopupMenuItem<HeaderAction>(
diff --git a/playground/frontend/lib/pages/playground/playground_page.dart b/playground/frontend/lib/pages/playground/playground_page.dart
index df2fbc5..1c3cf38 100644
--- a/playground/frontend/lib/pages/playground/playground_page.dart
+++ b/playground/frontend/lib/pages/playground/playground_page.dart
@@ -19,9 +19,10 @@
import 'package:flutter/material.dart';
import 'package:playground/components/toggle_theme_button/toggle_theme_button.dart';
import 'package:playground/constants/sizes.dart';
+import 'package:playground/modules/shortcuts/components/shortcuts_manager.dart';
+import 'package:playground/modules/shortcuts/constants/global_shortcuts.dart';
import 'package:playground/pages/playground/components/playground_page_body.dart';
import 'package:playground/pages/playground/components/playground_page_footer.dart';
-import 'package:playground/pages/playground/components/playground_page_providers.dart';
import 'package:playground/modules/actions/components/new_example_action.dart';
import 'package:playground/modules/actions/components/reset_action.dart';
import 'package:playground/pages/playground/components/more_actions.dart';
@@ -35,7 +36,8 @@ class PlaygroundPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return PlaygroundPageProviders(
+ return ShortcutsManager(
+ shortcuts: globalShortcuts,
child: Scaffold(
appBar: AppBar(
title: Consumer<PlaygroundState>(
diff --git a/playground/frontend/lib/pages/playground/states/playground_state.dart b/playground/frontend/lib/pages/playground/states/playground_state.dart
index 15f0d3a..8eb7cda 100644
--- a/playground/frontend/lib/pages/playground/states/playground_state.dart
+++ b/playground/frontend/lib/pages/playground/states/playground_state.dart
@@ -66,6 +66,11 @@ class PlaygroundState with ChangeNotifier {
_source = source;
}
+ clearOutput() {
+ _result = null;
+ notifyListeners();
+ }
+
reset() {
_sdk = SDK.java;
_source = _selectedExample?.sources[_sdk] ?? "";
diff --git a/playground/frontend/lib/playground_app.dart b/playground/frontend/lib/playground_app.dart
index 8ce11d1..54955d0 100644
--- a/playground/frontend/lib/playground_app.dart
+++ b/playground/frontend/lib/playground_app.dart
@@ -18,6 +18,7 @@
import 'package:flutter/material.dart';
import 'package:playground/config/theme.dart';
+import 'package:playground/pages/playground/components/playground_page_providers.dart';
import 'package:playground/pages/playground/playground_page.dart';
import 'package:provider/provider.dart';
@@ -30,13 +31,15 @@ class PlaygroundApp extends StatelessWidget {
create: (context) => ThemeProvider(),
builder: (context, _) {
final themeProvider = Provider.of<ThemeProvider>(context);
- return MaterialApp(
- title: 'Apache Beam Playground',
- themeMode: themeProvider.themeMode,
- theme: kLightTheme,
- darkTheme: kDarkTheme,
- home: const PlaygroundPage(),
- debugShowCheckedModeBanner: false,
+ return PlaygroundPageProviders(
+ child: MaterialApp(
+ title: 'Apache Beam Playground',
+ themeMode: themeProvider.themeMode,
+ theme: kLightTheme,
+ darkTheme: kDarkTheme,
+ home: const PlaygroundPage(),
+ debugShowCheckedModeBanner: false,
+ ),
);
},
);