diff --git a/.github/workflows/build_playground_frontend.yml b/.github/workflows/build_playground_frontend.yml
index f71fc314b7a2..a27ce08d07ae 100644
--- a/.github/workflows/build_playground_frontend.yml
+++ b/.github/workflows/build_playground_frontend.yml
@@ -37,7 +37,7 @@ jobs:
GO_VERSION: 1.18.0
BEAM_VERSION: 2.40.0
TERRAFORM_VERSION: 1.0.9
- FLUTTER_VERSION: 3.0.1-stable
+ FLUTTER_VERSION: 3.3.2
STAND_SUFFIX: ''
GOOGLE_DOMAIN: '-dot-apache-beam-testing.appspot.com'
steps:
@@ -49,8 +49,8 @@ jobs:
java-version: '8'
- name: install flutter
run: |
- wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_$FLUTTER_VERSION.tar.xz &&\
- tar -xf flutter_linux_$FLUTTER_VERSION.tar.xz &&\
+ wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_$FLUTTER_VERSION-stable.tar.xz &&\
+ tar -xf flutter_linux_$FLUTTER_VERSION-stable.tar.xz &&\
mv flutter /opt/ &&\
ln -s /opt/flutter/bin/flutter /usr/local/bin/flutter &&\
ln -s /opt/flutter/bin/dart /usr/local/bin/dart &&\
diff --git a/.gitignore b/.gitignore
index 443ced0aaeec..ec600f50f830 100644
--- a/.gitignore
+++ b/.gitignore
@@ -125,6 +125,7 @@ website/www/yarn-error.log
**/.flutter-plugins
**/.flutter-plugins-dependencies
**/generated_plugin_registrant.dart
+**/*.mocks.dart
# Ignore Beam Playground Terraform
**/.terraform
diff --git a/learning/tour-of-beam/frontend/assets/png/profile-website.png b/learning/tour-of-beam/frontend/assets/png/profile-website.png
new file mode 100644
index 000000000000..e0b25a42aafb
Binary files /dev/null and b/learning/tour-of-beam/frontend/assets/png/profile-website.png differ
diff --git a/learning/tour-of-beam/frontend/assets/svg/github-logo.svg b/learning/tour-of-beam/frontend/assets/svg/github-logo.svg
new file mode 100644
index 000000000000..495172be937c
--- /dev/null
+++ b/learning/tour-of-beam/frontend/assets/svg/github-logo.svg
@@ -0,0 +1,19 @@
+
+
+
\ No newline at end of file
diff --git a/learning/tour-of-beam/frontend/assets/svg/google-logo.svg b/learning/tour-of-beam/frontend/assets/svg/google-logo.svg
new file mode 100644
index 000000000000..b704ef2cc7c4
--- /dev/null
+++ b/learning/tour-of-beam/frontend/assets/svg/google-logo.svg
@@ -0,0 +1,22 @@
+
+
+
\ No newline at end of file
diff --git a/learning/tour-of-beam/frontend/assets/svg/profile-about.svg b/learning/tour-of-beam/frontend/assets/svg/profile-about.svg
new file mode 100644
index 000000000000..9096d879ce6e
--- /dev/null
+++ b/learning/tour-of-beam/frontend/assets/svg/profile-about.svg
@@ -0,0 +1,21 @@
+
+
+
\ No newline at end of file
diff --git a/learning/tour-of-beam/frontend/assets/svg/profile-delete.svg b/learning/tour-of-beam/frontend/assets/svg/profile-delete.svg
new file mode 100644
index 000000000000..2d801aba6e28
--- /dev/null
+++ b/learning/tour-of-beam/frontend/assets/svg/profile-delete.svg
@@ -0,0 +1,19 @@
+
+
+
\ No newline at end of file
diff --git a/learning/tour-of-beam/frontend/assets/svg/profile-logout.svg b/learning/tour-of-beam/frontend/assets/svg/profile-logout.svg
new file mode 100644
index 000000000000..9f4b5de09be7
--- /dev/null
+++ b/learning/tour-of-beam/frontend/assets/svg/profile-logout.svg
@@ -0,0 +1,19 @@
+
+
+
\ No newline at end of file
diff --git a/learning/tour-of-beam/frontend/assets/svg/unit-progress-0.svg b/learning/tour-of-beam/frontend/assets/svg/unit-progress-0.svg
new file mode 100644
index 000000000000..37d5945870d5
--- /dev/null
+++ b/learning/tour-of-beam/frontend/assets/svg/unit-progress-0.svg
@@ -0,0 +1,19 @@
+
+
+
diff --git a/learning/tour-of-beam/frontend/assets/svg/unit-progress-100.svg b/learning/tour-of-beam/frontend/assets/svg/unit-progress-100.svg
new file mode 100644
index 000000000000..8eb0cf172d20
--- /dev/null
+++ b/learning/tour-of-beam/frontend/assets/svg/unit-progress-100.svg
@@ -0,0 +1,19 @@
+
+
+
diff --git a/learning/tour-of-beam/frontend/assets/svg/welcome-progress-0.svg b/learning/tour-of-beam/frontend/assets/svg/welcome-progress-0.svg
index d80426bf7899..1b8d4d67d5ef 100644
--- a/learning/tour-of-beam/frontend/assets/svg/welcome-progress-0.svg
+++ b/learning/tour-of-beam/frontend/assets/svg/welcome-progress-0.svg
@@ -15,5 +15,5 @@ See the License for the specific language governing permissions and
limitations under the License. -->
diff --git a/learning/tour-of-beam/frontend/assets/translations/en.yaml b/learning/tour-of-beam/frontend/assets/translations/en.yaml
index b40cbfee09d6..8dff25f4f91e 100644
--- a/learning/tour-of-beam/frontend/assets/translations/en.yaml
+++ b/learning/tour-of-beam/frontend/assets/translations/en.yaml
@@ -16,24 +16,33 @@
# under the License.
ui:
- copyright: '© The Apache Software Foundation'
- darkMode: 'Dark Mode'
- lightMode: 'Light Mode'
- privacyPolicy: 'Privacy Policy'
- reportIssue: 'Report Issue in GitHub'
- signIn: 'Sign in'
- continueGitHub: 'Continue with GitHub'
- continueGoogle: 'Continue with Google'
+ about: About Tour of Beam
+ builtWith: Built with Apache Beam
+ continueGitHub: Continue with GitHub
+ continueGoogle: Continue with Google
+ copyright: © The Apache Software Foundation
+ deleteAccount: Delete my account
+ privacyPolicy: Privacy Policy
+ reportIssue: Report Issue in GitHub
+ signIn: Sign in
+ signOut: Sign out
+ toWebsite: To Apache Beam website
+
pages:
welcome:
- title: 'Welcome to the Tour of Beam!'
- ifSaveProgress: 'Your journey is broken down into learning modules. If you would like to save your progress and track completed modules, please'
- signIn: ' sign in.'
+ ifSaveProgress: Your journey is broken down into learning modules. If you would like to save your progress and track completed modules, please
selectLanguage: 'Please select the default language (you may change the language at any time):'
- startLearning: 'Start learning'
+ signIn: ' sign in.'
+ startTour: Start your tour
+ title: Welcome to the Tour of Beam!
+ tour:
+ completeUnit: Complete Unit
+ summaryTitle: Table of Contents
+
dialogs:
signInIf: If you would like to save your progress and track completed modules
+
complexity:
- basic: 'Basic level'
- medium: 'Medium level'
- advanced: 'Advanced level'
+ basic: Basic level
+ medium: Medium level
+ advanced: Advanced level
diff --git a/learning/tour-of-beam/frontend/integration_test/app_test.dart b/learning/tour-of-beam/frontend/integration_test/app_test.dart
index 232234bb0565..e74b4d35624f 100644
--- a/learning/tour-of-beam/frontend/integration_test/app_test.dart
+++ b/learning/tour-of-beam/frontend/integration_test/app_test.dart
@@ -19,7 +19,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
-import 'package:tour_of_beam/components/toggle_theme_button.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:tour_of_beam/main.dart' as app;
void main() {
diff --git a/learning/tour-of-beam/frontend/lib/components/expansion_tile_wrapper.dart b/learning/tour-of-beam/frontend/lib/components/expansion_tile_wrapper.dart
new file mode 100644
index 000000000000..b09e6177ef2f
--- /dev/null
+++ b/learning/tour-of-beam/frontend/lib/components/expansion_tile_wrapper.dart
@@ -0,0 +1,42 @@
+/*
+ * 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_components/playground_components.dart';
+
+class ExpansionTileWrapper extends StatelessWidget {
+ final ExpansionTile expansionTile;
+ const ExpansionTileWrapper(this.expansionTile);
+
+ @override
+ Widget build(BuildContext context) {
+ return Theme(
+ data: Theme.of(context).copyWith(
+ hoverColor: BeamColors.transparent,
+ splashColor: BeamColors.transparent,
+ highlightColor: BeamColors.transparent,
+ dividerColor: BeamColors.transparent,
+ unselectedWidgetColor: Colors.grey,
+ colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.grey),
+ visualDensity: const VisualDensity(vertical: -4),
+ listTileTheme: const ListTileThemeData(dense: true),
+ ),
+ child: expansionTile,
+ );
+ }
+}
diff --git a/learning/tour-of-beam/frontend/lib/components/filler_text.dart b/learning/tour-of-beam/frontend/lib/components/filler_text.dart
new file mode 100644
index 000000000000..ca6099e6d9de
--- /dev/null
+++ b/learning/tour-of-beam/frontend/lib/components/filler_text.dart
@@ -0,0 +1,29 @@
+/*
+ * 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';
+
+class FillerText extends StatelessWidget {
+ final int width;
+ const FillerText({required this.width});
+
+ @override
+ Widget build(BuildContext context) {
+ return Text(''.padRight(width, 'Just a filler text. '));
+ }
+}
diff --git a/learning/tour-of-beam/frontend/lib/components/footer.dart b/learning/tour-of-beam/frontend/lib/components/footer.dart
index b42fbca162ca..e801836bb898 100644
--- a/learning/tour-of-beam/frontend/lib/components/footer.dart
+++ b/learning/tour-of-beam/frontend/lib/components/footer.dart
@@ -18,10 +18,9 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:url_launcher/url_launcher.dart';
-import '../config/theme/colors_provider.dart';
-import '../constants/links.dart';
import '../constants/sizes.dart';
class Footer extends StatelessWidget {
@@ -31,12 +30,25 @@ class Footer extends StatelessWidget {
Widget build(BuildContext context) {
return _Body(
child: Wrap(
- spacing: TobSizes.size16,
+ alignment: WrapAlignment.spaceBetween,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
- const _ReportIssueButton(),
- const _PrivacyPolicyButton(),
- const Text('ui.copyright').tr(),
+ Wrap(
+ spacing: BeamSizes.size16,
+ crossAxisAlignment: WrapCrossAlignment.center,
+ children: [
+ const _ReportIssueButton(),
+ const _PrivacyPolicyButton(),
+ const Text('ui.copyright').tr(),
+ ],
+ ),
+ // TODO(nausharipov): get version, https://github.com/apache/beam/issues/23038
+ Text(
+ '${'ui.builtWith'.tr()} (TODO: Version)',
+ style: const TextStyle(
+ color: BeamColors.grey3,
+ ),
+ ),
],
),
);
@@ -49,19 +61,22 @@ class _Body extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final themeData = Theme.of(context);
+ final ext = themeData.extension()!;
+
return Container(
+ width: double.infinity,
+ height: TobSizes.footerHeight,
padding: const EdgeInsets.symmetric(
- vertical: TobSizes.size4,
- horizontal: TobSizes.size16,
+ vertical: BeamSizes.size4,
+ horizontal: BeamSizes.size16,
),
decoration: BoxDecoration(
- color: ThemeColors.of(context).secondaryBackground,
+ color: ext.secondaryBackgroundColor,
border: Border(
- top: BorderSide(color: ThemeColors.of(context).divider),
+ top: BorderSide(color: themeData.dividerColor),
),
),
- height: TobSizes.footerHeight,
- width: double.infinity,
child: child,
);
}
@@ -75,7 +90,7 @@ class _ReportIssueButton extends StatelessWidget {
return TextButton(
style: _linkButtonStyle,
onPressed: () {
- launchUrl(Uri.parse(TobLinks.reportIssue));
+ launchUrl(Uri.parse(BeamLinks.reportIssue));
},
child: const Text('ui.reportIssue').tr(),
);
@@ -90,7 +105,7 @@ class _PrivacyPolicyButton extends StatelessWidget {
return TextButton(
style: _linkButtonStyle,
onPressed: () {
- launchUrl(Uri.parse(TobLinks.privacyPolicy));
+ launchUrl(Uri.parse(BeamLinks.privacyPolicy));
},
child: const Text('ui.privacyPolicy').tr(),
);
diff --git a/learning/tour-of-beam/frontend/lib/components/sign_in/sign_in_button.dart b/learning/tour-of-beam/frontend/lib/components/login/login_button.dart
similarity index 72%
rename from learning/tour-of-beam/frontend/lib/components/sign_in/sign_in_button.dart
rename to learning/tour-of-beam/frontend/lib/components/login/login_button.dart
index b823ea71c1b1..36d96faffe5a 100644
--- a/learning/tour-of-beam/frontend/lib/components/sign_in/sign_in_button.dart
+++ b/learning/tour-of-beam/frontend/lib/components/login/login_button.dart
@@ -18,28 +18,24 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
-import 'package:playground_components/dismissible_overlay.dart';
+import 'package:playground_components/playground_components.dart';
-import '../../constants/sizes.dart';
-import 'sign_in_overlay_content.dart';
+import 'login_content.dart';
-class SignInButton extends StatefulWidget {
- const SignInButton();
+class LoginButton extends StatelessWidget {
+ const LoginButton();
- @override
- State createState() => _SignInButtonState();
-}
-
-class _SignInButtonState extends State {
@override
Widget build(BuildContext context) {
return TextButton(
- onPressed: _openOverlay,
+ onPressed: () {
+ _openOverlay(context);
+ },
child: const Text('ui.signIn').tr(),
);
}
- void _openOverlay() {
+ void _openOverlay(BuildContext context) {
OverlayEntry? overlay;
overlay = OverlayEntry(
builder: (context) => DismissibleOverlay(
@@ -47,9 +43,9 @@ class _SignInButtonState extends State {
overlay?.remove();
},
child: const Positioned(
- right: TobSizes.size10,
- top: TobSizes.appBarHeight,
- child: SignInOverlayContent(),
+ right: BeamSizes.size10,
+ top: BeamSizes.appBarHeight,
+ child: LoginContent(),
),
),
);
diff --git a/learning/tour-of-beam/frontend/lib/components/login/login_content.dart b/learning/tour-of-beam/frontend/lib/components/login/login_content.dart
new file mode 100644
index 000000000000..d4d0d8873cce
--- /dev/null
+++ b/learning/tour-of-beam/frontend/lib/components/login/login_content.dart
@@ -0,0 +1,140 @@
+/*
+ * 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:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:playground_components/playground_components.dart';
+
+import '../../constants/sizes.dart';
+import '../../generated/assets.gen.dart';
+
+class LoginContent extends StatelessWidget {
+ const LoginContent();
+
+ @override
+ Widget build(BuildContext context) {
+ return _Body(
+ child: Column(
+ children: [
+ Text(
+ 'ui.signIn',
+ style: Theme.of(context).textTheme.titleLarge,
+ ).tr(),
+ const SizedBox(height: BeamSizes.size10),
+ const Text(
+ 'dialogs.signInIf',
+ textAlign: TextAlign.center,
+ ).tr(),
+ const _Divider(),
+ const _BrandedLoginButtons(),
+ ],
+ ),
+ );
+ }
+}
+
+class _Body extends StatelessWidget {
+ final Widget child;
+ const _Body({required this.child});
+
+ @override
+ Widget build(BuildContext context) {
+ return Material(
+ elevation: BeamSizes.size10,
+ borderRadius: BorderRadius.circular(10),
+ child: Container(
+ width: TobSizes.authOverlayWidth,
+ padding: const EdgeInsets.all(BeamSizes.size24),
+ child: child,
+ ),
+ );
+ }
+}
+
+class _Divider extends StatelessWidget {
+ const _Divider();
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ color: BeamColors.grey3,
+ margin: const EdgeInsets.symmetric(vertical: 20),
+ width: BeamSizes.size32,
+ height: BeamSizes.size1,
+ );
+ }
+}
+
+class _BrandedLoginButtons extends StatelessWidget {
+ const _BrandedLoginButtons();
+
+ @override
+ Widget build(BuildContext context) {
+ final isLightTheme = Theme.of(context).brightness == Brightness.light;
+ final textStyle =
+ MaterialStatePropertyAll(Theme.of(context).textTheme.bodyMedium);
+ const padding = MaterialStatePropertyAll(
+ EdgeInsets.symmetric(
+ vertical: BeamSizes.size20,
+ horizontal: BeamSizes.size24,
+ ),
+ );
+ const minimumSize = MaterialStatePropertyAll(Size(double.infinity, 0));
+
+ final darkButtonStyle = ButtonStyle(
+ backgroundColor: const MaterialStatePropertyAll(BeamColors.darkGrey),
+ minimumSize: minimumSize,
+ padding: padding,
+ textStyle: textStyle,
+ );
+ final githubLightButtonStyle = ButtonStyle(
+ backgroundColor: const MaterialStatePropertyAll(BeamColors.darkBlue),
+ minimumSize: minimumSize,
+ padding: padding,
+ textStyle: textStyle,
+ );
+ final googleLightButtonStyle = ButtonStyle(
+ backgroundColor: const MaterialStatePropertyAll(BeamColors.white),
+ elevation: const MaterialStatePropertyAll(BeamSizes.size4),
+ foregroundColor: const MaterialStatePropertyAll(BeamColors.black),
+ minimumSize: minimumSize,
+ overlayColor: MaterialStatePropertyAll(Theme.of(context).hoverColor),
+ padding: padding,
+ textStyle: textStyle,
+ );
+
+ return Column(
+ children: [
+ ElevatedButton.icon(
+ onPressed: () {},
+ style: isLightTheme ? githubLightButtonStyle : darkButtonStyle,
+ icon: SvgPicture.asset(Assets.svg.githubLogo),
+ label: const Text('ui.continueGitHub').tr(),
+ ),
+ const SizedBox(height: BeamSizes.size16),
+ ElevatedButton.icon(
+ onPressed: () {},
+ style: isLightTheme ? googleLightButtonStyle : darkButtonStyle,
+ icon: SvgPicture.asset(Assets.svg.googleLogo),
+ label: const Text('ui.continueGoogle').tr(),
+ ),
+ ],
+ );
+ }
+}
diff --git a/learning/tour-of-beam/frontend/lib/components/logo.dart b/learning/tour-of-beam/frontend/lib/components/logo.dart
index e48b3985bf6b..913678c76bd5 100644
--- a/learning/tour-of-beam/frontend/lib/components/logo.dart
+++ b/learning/tour-of-beam/frontend/lib/components/logo.dart
@@ -17,9 +17,7 @@
*/
import 'package:flutter/material.dart';
-
-import '../constants/assets.dart';
-import '../constants/sizes.dart';
+import 'package:playground_components/playground_components.dart';
class Logo extends StatelessWidget {
const Logo();
@@ -28,12 +26,9 @@ class Logo extends StatelessWidget {
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
- children: [
- Image.asset(
- TobAssets.beamLogo,
- height: TobIconSizes.large,
- ),
- const _Text(),
+ children: const [
+ BeamLogo(),
+ _Text(),
],
);
}
diff --git a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart
new file mode 100644
index 000000000000..959c83876e3c
--- /dev/null
+++ b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart
@@ -0,0 +1,57 @@
+/*
+ * 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_components/playground_components.dart';
+
+import '../../generated/assets.gen.dart';
+import 'profile_content.dart';
+
+class Avatar extends StatelessWidget {
+ const Avatar();
+
+ @override
+ Widget build(BuildContext context) {
+ return GestureDetector(
+ onTap: () {
+ _openOverlay(context);
+ },
+ child: CircleAvatar(
+ backgroundColor: BeamColors.white,
+ foregroundImage: AssetImage(Assets.png.laptopLight.path),
+ ),
+ );
+ }
+
+ void _openOverlay(BuildContext context) {
+ OverlayEntry? overlay;
+ overlay = OverlayEntry(
+ builder: (context) => DismissibleOverlay(
+ close: () {
+ overlay?.remove();
+ },
+ child: const Positioned(
+ right: BeamSizes.size10,
+ top: BeamSizes.appBarHeight,
+ child: ProfileContent(),
+ ),
+ ),
+ );
+ Overlay.of(context)?.insert(overlay);
+ }
+}
diff --git a/learning/tour-of-beam/frontend/lib/components/profile/profile_content.dart b/learning/tour-of-beam/frontend/lib/components/profile/profile_content.dart
new file mode 100644
index 000000000000..65f039dad326
--- /dev/null
+++ b/learning/tour-of-beam/frontend/lib/components/profile/profile_content.dart
@@ -0,0 +1,160 @@
+/*
+ * 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:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:playground_components/playground_components.dart';
+
+import '../../constants/sizes.dart';
+import '../../generated/assets.gen.dart';
+
+class ProfileContent extends StatelessWidget {
+ const ProfileContent();
+
+ @override
+ Widget build(BuildContext context) {
+ return _Body(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: const [
+ _Info(),
+ BeamDivider(),
+ _Buttons(),
+ ],
+ ),
+ );
+ }
+}
+
+class _Body extends StatelessWidget {
+ final Widget child;
+
+ const _Body({required this.child});
+
+ @override
+ Widget build(BuildContext context) {
+ return Material(
+ elevation: BeamSizes.size10,
+ borderRadius: BorderRadius.circular(10),
+ child: SizedBox(
+ width: TobSizes.authOverlayWidth,
+ child: child,
+ ),
+ );
+ }
+}
+
+class _Info extends StatelessWidget {
+ const _Info();
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.all(BeamSizes.size16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ 'Name Surname',
+ style: Theme.of(context).textTheme.titleLarge,
+ ),
+ Text(
+ 'email@mail.com',
+ style: Theme.of(context).textTheme.bodySmall,
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class _Buttons extends StatelessWidget {
+ const _Buttons();
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ _IconLabel(
+ isSvg: false,
+ onTap: () {},
+ iconPath: Assets.png.profileWebsite.path,
+ label: 'ui.toWebsite'.tr(),
+ ),
+ const BeamDivider(),
+ _IconLabel(
+ onTap: () {},
+ iconPath: Assets.svg.profileAbout,
+ label: 'ui.about'.tr(),
+ ),
+ const BeamDivider(),
+ _IconLabel(
+ onTap: () {},
+ iconPath: Assets.svg.profileLogout,
+ label: 'ui.signOut'.tr(),
+ ),
+ const BeamDivider(),
+ _IconLabel(
+ onTap: () {},
+ iconPath: Assets.svg.profileDelete,
+ label: 'ui.deleteAccount'.tr(),
+ ),
+ ],
+ );
+ }
+}
+
+class _IconLabel extends StatelessWidget {
+ final String iconPath;
+ final String label;
+ final void Function()? onTap;
+
+ // TODO(nausharipov): Auto-determine.
+ final bool isSvg;
+
+ const _IconLabel({
+ required this.iconPath,
+ required this.label,
+ required this.onTap,
+ this.isSvg = true,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return InkWell(
+ onTap: onTap,
+ child: Padding(
+ padding: const EdgeInsets.all(BeamSizes.size12),
+ child: Row(
+ children: [
+ if (isSvg)
+ SvgPicture.asset(iconPath)
+ else
+ Image.asset(
+ iconPath,
+ height: 20,
+ ),
+ const SizedBox(width: BeamSizes.size10),
+ Text(label),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/learning/tour-of-beam/frontend/lib/components/scaffold.dart b/learning/tour-of-beam/frontend/lib/components/scaffold.dart
new file mode 100644
index 000000000000..f8352140436e
--- /dev/null
+++ b/learning/tour-of-beam/frontend/lib/components/scaffold.dart
@@ -0,0 +1,77 @@
+/*
+ * 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_components/playground_components.dart';
+
+import 'footer.dart';
+import 'login/login_button.dart';
+import 'logo.dart';
+import 'profile/avatar.dart';
+import 'sdk_dropdown.dart';
+
+class TobScaffold extends StatelessWidget {
+ final Widget child;
+
+ const TobScaffold({
+ super.key,
+ required this.child,
+ });
+
+ // TODO(nausharipov): get state
+ static const _isAuthorized = true;
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Logo(),
+ actions: const [
+ _ActionVerticalPadding(child: SdkDropdown()),
+ SizedBox(width: BeamSizes.size12),
+ _ActionVerticalPadding(child: ToggleThemeButton()),
+ SizedBox(width: BeamSizes.size6),
+ _ActionVerticalPadding(
+ child: _isAuthorized ? Avatar() : LoginButton(),
+ ),
+ SizedBox(width: BeamSizes.size16),
+ ],
+ ),
+ body: Column(
+ children: [
+ Expanded(child: child),
+ const Footer(),
+ ],
+ ),
+ );
+ }
+}
+
+class _ActionVerticalPadding extends StatelessWidget {
+ final Widget child;
+
+ const _ActionVerticalPadding({required this.child});
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.symmetric(vertical: BeamSizes.size10),
+ child: child,
+ );
+ }
+}
diff --git a/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart
new file mode 100644
index 000000000000..47f1a728b8ea
--- /dev/null
+++ b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart
@@ -0,0 +1,64 @@
+/*
+ * 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_components/playground_components.dart';
+
+class SdkDropdown extends StatelessWidget {
+ const SdkDropdown();
+
+ @override
+ Widget build(BuildContext context) {
+ return _DropdownWrapper(
+ child: DropdownButton(
+ value: 'Java',
+ onChanged: (sdk) {
+ // TODO(nausharipov): change SDK
+ },
+ items: const ['Java', 'Python', 'Go']
+ .map(
+ (sdk) => DropdownMenuItem(
+ value: sdk,
+ child: Text(sdk),
+ ),
+ )
+ .toList(growable: false),
+ isDense: true,
+ alignment: Alignment.center,
+ focusColor: BeamColors.transparent,
+ borderRadius: BorderRadius.circular(BeamSizes.size6),
+ ),
+ );
+ }
+}
+
+class _DropdownWrapper extends StatelessWidget {
+ final Widget child;
+ const _DropdownWrapper({required this.child});
+
+ @override
+ Widget build(BuildContext context) {
+ return DecoratedBox(
+ decoration: BoxDecoration(
+ color: Theme.of(context).hoverColor,
+ borderRadius: BorderRadius.circular(BeamSizes.size6),
+ ),
+ child: DropdownButtonHideUnderline(child: child),
+ );
+ }
+}
diff --git a/learning/tour-of-beam/frontend/lib/components/sign_in/sign_in_overlay_content.dart b/learning/tour-of-beam/frontend/lib/components/sign_in/sign_in_overlay_content.dart
deleted file mode 100644
index 80fb00805e25..000000000000
--- a/learning/tour-of-beam/frontend/lib/components/sign_in/sign_in_overlay_content.dart
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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:easy_localization/easy_localization.dart';
-import 'package:flutter/material.dart';
-
-import '../../../constants/colors.dart';
-import '../../../constants/sizes.dart';
-
-class SignInOverlayContent extends StatelessWidget {
- const SignInOverlayContent();
-
- @override
- Widget build(BuildContext context) {
- return _Body(
- child: Column(
- children: [
- Text(
- 'ui.signIn',
- style: Theme.of(context).textTheme.titleLarge,
- ).tr(),
- const SizedBox(height: TobSizes.size10),
- const Text(
- 'dialogs.signInIf',
- textAlign: TextAlign.center,
- ).tr(),
- const _Divider(),
- // TODO(nausharipov): check branded buttons in firebase_auth
- ElevatedButton(
- onPressed: () {},
- child: const Text('ui.continueGitHub').tr(),
- ),
- const SizedBox(height: TobSizes.size16),
- ElevatedButton(
- onPressed: () {},
- child: const Text('ui.continueGoogle').tr(),
- ),
- ],
- ),
- );
- }
-}
-
-class _Body extends StatelessWidget {
- final Widget child;
- const _Body({required this.child});
-
- @override
- Widget build(BuildContext context) {
- return Material(
- elevation: TobSizes.size10,
- borderRadius: BorderRadius.circular(10),
- child: Container(
- width: TobSizes.authOverlayWidth,
- padding: const EdgeInsets.all(TobSizes.size24),
- child: child,
- ),
- );
- }
-}
-
-class _Divider extends StatelessWidget {
- const _Divider();
-
- @override
- Widget build(BuildContext context) {
- return Container(
- margin: const EdgeInsets.symmetric(vertical: 20),
- width: TobSizes.size32,
- height: TobSizes.size1,
- color: TobColors.grey3,
- );
- }
-}
diff --git a/learning/tour-of-beam/frontend/lib/config/theme/colors_provider.dart b/learning/tour-of-beam/frontend/lib/config/theme/colors_provider.dart
deleted file mode 100644
index 3aab5a1703ca..000000000000
--- a/learning/tour-of-beam/frontend/lib/config/theme/colors_provider.dart
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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:provider/provider.dart';
-
-import '../../constants/colors.dart';
-
-class ThemeColorsProvider extends StatelessWidget {
- final ThemeColors data;
- final Widget child;
-
- const ThemeColorsProvider({
- super.key,
- required this.data,
- required this.child,
- });
-
- @override
- Widget build(BuildContext context) {
- return Provider.value(
- value: data,
- child: child,
- );
- }
-}
-
-class ThemeColors {
- final Color? _background;
- final bool isDark;
-
- ThemeColors({
- required this.isDark,
- Color? background,
- }) : _background = background;
-
- static ThemeColors of(BuildContext context, {bool listen = true}) {
- return Provider.of(context, listen: listen);
- }
-
- const ThemeColors.fromBrightness({
- required this.isDark,
- }) : _background = null;
-
- Color get divider =>
- isDark ? TobDarkThemeColors.grey : TobLightThemeColors.grey;
-
- Color get primary =>
- isDark ? TobDarkThemeColors.primary : TobLightThemeColors.primary;
-
- Color get primaryBackgroundTextColor => TobColors.white;
-
- Color get lightGreyBackgroundTextColor => TobColors.black;
-
- Color get secondaryBackground => isDark
- ? TobDarkThemeColors.secondaryBackground
- : TobLightThemeColors.secondaryBackground;
-
- Color get background =>
- _background ??
- (isDark
- ? TobDarkThemeColors.primaryBackground
- : TobLightThemeColors.primaryBackground);
-
- Color get textColor =>
- isDark ? TobDarkThemeColors.text : TobLightThemeColors.text;
-
- Color get progressBackgroundColor =>
- // TODO(nausharipov): reuse these colors after discussion with Anna
- isDark ? const Color(0xffFFFFFF) : const Color(0xff242639);
-}
diff --git a/learning/tour-of-beam/frontend/lib/config/theme/theme.dart b/learning/tour-of-beam/frontend/lib/config/theme/theme.dart
deleted file mode 100644
index d8cf2c1c2086..000000000000
--- a/learning/tour-of-beam/frontend/lib/config/theme/theme.dart
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * 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:google_fonts/google_fonts.dart';
-
-import '../../constants/colors.dart';
-import '../../constants/sizes.dart';
-
-final kLightTheme = ThemeData(
- brightness: Brightness.light,
- primaryColor: TobLightThemeColors.primary,
- canvasColor: TobLightThemeColors.primaryBackground,
- scaffoldBackgroundColor: TobLightThemeColors.secondaryBackground,
- backgroundColor: TobLightThemeColors.primaryBackground,
- textTheme: _getTextTheme(TobLightThemeColors.text),
- textButtonTheme: _getTextButtonTheme(TobLightThemeColors.text),
- outlinedButtonTheme: _getOutlineButtonTheme(
- TobLightThemeColors.text,
- TobLightThemeColors.primary,
- ),
- elevatedButtonTheme: _getElevatedButtonTheme(TobLightThemeColors.primary),
- appBarTheme: _getAppBarTheme(TobLightThemeColors.secondaryBackground),
-);
-
-final kDarkTheme = ThemeData(
- brightness: Brightness.dark,
- primaryColor: TobDarkThemeColors.primary,
- canvasColor: TobDarkThemeColors.primaryBackground,
- scaffoldBackgroundColor: TobDarkThemeColors.secondaryBackground,
- backgroundColor: TobDarkThemeColors.primaryBackground,
- textTheme: _getTextTheme(TobDarkThemeColors.text),
- textButtonTheme: _getTextButtonTheme(TobDarkThemeColors.text),
- outlinedButtonTheme: _getOutlineButtonTheme(
- TobDarkThemeColors.text,
- TobDarkThemeColors.primary,
- ),
- elevatedButtonTheme: _getElevatedButtonTheme(TobDarkThemeColors.primary),
- appBarTheme: _getAppBarTheme(TobDarkThemeColors.secondaryBackground),
-);
-
-TextTheme _getTextTheme(Color textColor) {
- return GoogleFonts.sourceSansProTextTheme(
- const TextTheme(
- displayLarge: _emptyTextStyle,
- displayMedium: TextStyle(
- fontSize: 48,
- fontWeight: FontWeight.w900,
- ),
- displaySmall: TextStyle(
- fontFamily: 'Roboto_regular',
- fontSize: 18,
- fontWeight: FontWeight.w400,
- ),
- headlineLarge: _emptyTextStyle,
- headlineMedium: _emptyTextStyle,
- headlineSmall: TextStyle(
- fontSize: 12,
- fontWeight: FontWeight.w600,
- ),
- titleLarge: TextStyle(
- fontSize: 24,
- fontWeight: FontWeight.w600,
- ),
- titleMedium: _emptyTextStyle,
- titleSmall: _emptyTextStyle,
- labelLarge: TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w600,
- ),
- labelMedium: _emptyTextStyle,
- labelSmall: _emptyTextStyle,
- bodyLarge: TextStyle(
- fontSize: 24,
- fontWeight: FontWeight.w400,
- ),
- bodyMedium: TextStyle(
- fontSize: 13,
- fontWeight: FontWeight.w400,
- ),
- bodySmall: _emptyTextStyle,
- ).apply(
- bodyColor: textColor,
- displayColor: textColor,
- ),
- );
-}
-
-TextButtonThemeData _getTextButtonTheme(Color textColor) {
- return TextButtonThemeData(
- style: TextButton.styleFrom(
- primary: textColor,
- shape: _getButtonBorder(TobBorderRadius.large),
- ),
- );
-}
-
-OutlinedButtonThemeData _getOutlineButtonTheme(
- Color textColor,
- Color outlineColor,
-) {
- return OutlinedButtonThemeData(
- style: OutlinedButton.styleFrom(
- primary: textColor,
- side: BorderSide(color: outlineColor, width: 3),
- padding: _buttonPadding,
- shape: _getButtonBorder(TobBorderRadius.small),
- ),
- );
-}
-
-ElevatedButtonThemeData _getElevatedButtonTheme(Color color) {
- return ElevatedButtonThemeData(
- style: ElevatedButton.styleFrom(
- onPrimary: TobColors.white,
- primary: color,
- padding: _buttonPadding,
- elevation: TobSizes.size0,
- ),
- );
-}
-
-AppBarTheme _getAppBarTheme(Color backgroundColor) {
- return AppBarTheme(
- color: backgroundColor,
- elevation: TobSizes.size1,
- centerTitle: false,
- toolbarHeight: TobSizes.appBarHeight,
- );
-}
-
-const EdgeInsets _buttonPadding = EdgeInsets.symmetric(
- vertical: TobSizes.size20,
- horizontal: TobSizes.size40,
-);
-
-RoundedRectangleBorder _getButtonBorder(double radius) {
- return RoundedRectangleBorder(
- borderRadius: BorderRadius.all(
- Radius.circular(radius),
- ),
- );
-}
-
-const TextStyle _emptyTextStyle = TextStyle();
diff --git a/learning/tour-of-beam/frontend/lib/constants/assets.dart b/learning/tour-of-beam/frontend/lib/constants/assets.dart
deleted file mode 100644
index 1af152cc402b..000000000000
--- a/learning/tour-of-beam/frontend/lib/constants/assets.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.
- */
-
-String _getPngPath(String fileName) {
- return 'png/$fileName.png';
-}
-
-String _getSvgPath(String fileName) {
- return 'svg/$fileName.svg';
-}
-
-class TobAssets {
- static final beamLogo = _getPngPath('beam-logo');
- static final themeMode = _getSvgPath('theme-mode');
- static final welcomeLaptop = _getPngPath('welcome-laptop');
- static final laptopDark = _getPngPath('laptop-dark');
- static final laptopLight = _getPngPath('laptop-light');
- static final welcomeProgress0 = _getSvgPath('welcome-progress-0');
-}
diff --git a/learning/tour-of-beam/frontend/lib/constants/sizes.dart b/learning/tour-of-beam/frontend/lib/constants/sizes.dart
index 187a0f60f952..bb9a665c8a30 100644
--- a/learning/tour-of-beam/frontend/lib/constants/sizes.dart
+++ b/learning/tour-of-beam/frontend/lib/constants/sizes.dart
@@ -17,36 +17,8 @@
*/
class TobSizes {
- static const double size0 = 0;
- static const double size1 = 1;
- static const double size4 = 4;
- static const double size6 = 6;
- static const double size8 = 8;
- static const double size10 = 10;
- static const double size12 = 12;
- static const double size16 = 16;
- static const double size20 = 20;
- static const double size24 = 24;
- static const double size32 = 32;
- static const double size36 = 36;
- static const double size40 = 40;
- static const double appBarHeight = 55;
- static const double footerHeight = 30;
- static const double authOverlayWidth = 300;
-}
-
-class TobBorderRadius {
- static const double small = 4;
- static const double medium = 6;
- static const double large = 8;
- static const double xl = 28;
-}
-
-class TobIconSizes {
- static const double xs = 8;
- static const double small = 16;
- static const double medium = 24;
- static const double large = 32;
+ static const double footerHeight = 35;
+ static const double authOverlayWidth = 260;
}
class ScreenSizes {
diff --git a/learning/tour-of-beam/frontend/lib/main.dart b/learning/tour-of-beam/frontend/lib/main.dart
index 4c81d88a4f51..c7eb698c3782 100644
--- a/learning/tour-of-beam/frontend/lib/main.dart
+++ b/learning/tour-of-beam/frontend/lib/main.dart
@@ -17,15 +17,15 @@
*/
import 'package:easy_localization/easy_localization.dart';
+import 'package:easy_localization_ext/easy_localization_ext.dart';
import 'package:easy_localization_loader/easy_localization_loader.dart';
import 'package:flutter/material.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:provider/provider.dart';
import 'package:url_strategy/url_strategy.dart';
-import 'config/theme/switch_notifier.dart';
-import 'config/theme/theme.dart';
import 'locator.dart';
-import 'pages/welcome/screen.dart';
+import 'pages/tour/screen.dart';
void main() async {
setPathUrlStrategy();
@@ -39,7 +39,10 @@ void main() async {
startLocale: englishLocale,
fallbackLocale: englishLocale,
path: 'assets/translations',
- assetLoader: YamlAssetLoader(),
+ assetLoader: MultiAssetLoader([
+ PlaygroundComponents.translationLoader,
+ YamlAssetLoader(),
+ ]),
child: const TourOfBeamApp(),
),
);
@@ -61,7 +64,7 @@ class TourOfBeamApp extends StatelessWidget {
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
- home: const WelcomeScreen(),
+ home: const TourScreen(),
);
},
),
diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/playground_demo.dart b/learning/tour-of-beam/frontend/lib/pages/tour/playground_demo.dart
new file mode 100644
index 000000000000..384d46b0fc29
--- /dev/null
+++ b/learning/tour-of-beam/frontend/lib/pages/tour/playground_demo.dart
@@ -0,0 +1,126 @@
+/*
+ * 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/widgets.dart';
+import 'package:playground_components/playground_components.dart';
+
+// This is for demo only. Need a thought-through import in production.
+
+const String kApiClientURL =
+ 'https://backend-router-beta-dot-apache-beam-testing.appspot.com';
+const String kApiJavaClientURL =
+ 'https://backend-java-beta-dot-apache-beam-testing.appspot.com';
+const String kApiGoClientURL =
+ 'https://backend-go-beta-dot-apache-beam-testing.appspot.com';
+const String kApiPythonClientURL =
+ 'https://backend-python-beta-dot-apache-beam-testing.appspot.com';
+const String kApiScioClientURL =
+ 'https://backend-scio-beta-dot-apache-beam-testing.appspot.com';
+
+class PlaygroundDemoWidget extends StatefulWidget {
+ const PlaygroundDemoWidget({super.key});
+
+ @override
+ State createState() => _PlaygroundDemoWidgetState();
+}
+
+class _PlaygroundDemoWidgetState extends State {
+ late final PlaygroundController playgroundController;
+
+ @override
+ void initState() {
+ super.initState();
+
+ final exampleRepository = ExampleRepository(
+ client: GrpcExampleClient(url: kApiClientURL),
+ );
+
+ final codeRepository = CodeRepository(
+ client: GrpcCodeClient(
+ url: kApiClientURL,
+ runnerUrlsById: {
+ Sdk.java.id: kApiJavaClientURL,
+ Sdk.go.id: kApiGoClientURL,
+ Sdk.python.id: kApiPythonClientURL,
+ Sdk.scio.id: kApiScioClientURL,
+ },
+ ),
+ );
+
+ final exampleCache = ExampleCache(
+ exampleRepository: exampleRepository,
+ hasCatalog: true,
+ );
+
+ playgroundController = PlaygroundController(
+ codeRepository: codeRepository,
+ exampleCache: exampleCache,
+ examplesLoader: ExamplesLoader(),
+ );
+
+ playgroundController.examplesLoader.load(
+ const ExamplesLoadingDescriptor(
+ descriptors: [
+ CatalogDefaultExampleLoadingDescriptor(sdk: Sdk.java),
+ ],
+ ),
+ );
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return AnimatedBuilder(
+ animation: playgroundController,
+ builder: _buildOnChange,
+ );
+ }
+
+ Widget _buildOnChange(BuildContext context, Widget? child) {
+ final snippetController = playgroundController.snippetEditingController;
+ if (snippetController == null) {
+ return const LoadingIndicator();
+ }
+
+ return Stack(
+ children: [
+ SplitView(
+ direction: Axis.vertical,
+ first: SnippetEditor(
+ controller: snippetController,
+ isEditable: true,
+ goToContextLine: false,
+ ),
+ second: OutputWidget(
+ playgroundController: playgroundController,
+ graphDirection: Axis.horizontal,
+ ),
+ ),
+ Positioned(
+ top: 30,
+ right: 30,
+ child: Row(
+ children: [
+ RunOrCancelButton(playgroundController: playgroundController),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart
new file mode 100644
index 000000000000..7d708ff25089
--- /dev/null
+++ b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart
@@ -0,0 +1,359 @@
+/*
+ * 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:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:playground_components/playground_components.dart';
+
+import '../../components/expansion_tile_wrapper.dart';
+import '../../components/filler_text.dart';
+import '../../components/scaffold.dart';
+import '../../constants/sizes.dart';
+import '../../generated/assets.gen.dart';
+import 'playground_demo.dart';
+
+class TourScreen extends StatelessWidget {
+ const TourScreen();
+
+ @override
+ Widget build(BuildContext context) {
+ return TobScaffold(
+ child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns
+ ? const _WideTour()
+ : const _NarrowTour(),
+ );
+ }
+}
+
+class _WideTour extends StatelessWidget {
+ const _WideTour();
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: const [
+ _ContentTree(),
+ Expanded(
+ child: SplitView(
+ direction: Axis.horizontal,
+ first: _Content(),
+ second: PlaygroundDemoWidget(),
+ ),
+ ),
+ ],
+ );
+ }
+}
+
+class _NarrowTour extends StatelessWidget {
+ const _NarrowTour();
+
+ @override
+ Widget build(BuildContext context) {
+ return SingleChildScrollView(
+ child: Column(
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: const [
+ _ContentTree(),
+ Expanded(child: _Content()),
+ ],
+ ),
+ DecoratedBox(
+ decoration: BoxDecoration(
+ border: Border(
+ top: BorderSide(color: Theme.of(context).dividerColor),
+ ),
+ ),
+ child: const _NarrowScreenPlayground(),
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class _ContentTree extends StatelessWidget {
+ const _ContentTree();
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ width: 250,
+ padding: const EdgeInsets.symmetric(horizontal: BeamSizes.size12),
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+ const _ContentTreeTitle(),
+ ...[
+ 'Core Transforms',
+ 'Common Transforms',
+ ].map((e) => _Module(module: e)).toList(growable: false),
+ const SizedBox(height: BeamSizes.size12),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+class _Module extends StatelessWidget {
+ final String module;
+ const _Module({required this.module});
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ _ModuleTitle(title: module),
+ ...['Map', 'Combine']
+ .map((group) => _Group(group: group))
+ .toList(growable: false),
+ const BeamDivider(
+ margin: EdgeInsets.symmetric(vertical: BeamSizes.size10),
+ ),
+ ],
+ );
+ }
+}
+
+class _ContentTreeTitle extends StatelessWidget {
+ const _ContentTreeTitle();
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.symmetric(vertical: BeamSizes.size12),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ 'pages.tour.summaryTitle',
+ style: Theme.of(context).textTheme.headlineLarge,
+ ).tr(),
+ ],
+ ),
+ );
+ }
+}
+
+class _ModuleTitle extends StatelessWidget {
+ final String title;
+ const _ModuleTitle({required this.title});
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: BeamSizes.size6),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ title,
+ style: Theme.of(context).textTheme.headlineMedium,
+ ),
+ const Padding(
+ padding: EdgeInsets.only(right: BeamSizes.size4),
+ child: ComplexityWidget(complexity: Complexity.basic),
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class _Group extends StatelessWidget {
+ final String group;
+ const _Group({required this.group});
+
+ @override
+ Widget build(BuildContext context) {
+ return ExpansionTileWrapper(
+ ExpansionTile(
+ tilePadding: EdgeInsets.zero,
+ title: _GroupTitle(title: group),
+ childrenPadding: const EdgeInsets.only(
+ left: BeamSizes.size24,
+ top: BeamSizes.size10,
+ ),
+ children: const [_Units()],
+ ),
+ );
+ }
+}
+
+class _Units extends StatelessWidget {
+ const _Units();
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: ['ParDo one-to-one', 'ParDo one-to-many']
+ .map((e) => _Unit(title: e))
+ .toList(growable: false),
+ );
+ }
+}
+
+class _Unit extends StatelessWidget {
+ final String title;
+ const _Unit({required this.title});
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: BeamSizes.size18),
+ child: Row(
+ children: [
+ _ProgressIndicator(
+ assetPath: Assets.svg.unitProgress100,
+ ),
+ Text(title),
+ ],
+ ),
+ );
+ }
+}
+
+class _GroupTitle extends StatelessWidget {
+ final String title;
+ const _GroupTitle({required this.title});
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ children: [
+ _ProgressIndicator(
+ assetPath: Assets.svg.unitProgress100,
+ ),
+ Text(
+ title,
+ style: Theme.of(context).textTheme.headlineMedium,
+ ),
+ ],
+ );
+ }
+}
+
+class _ProgressIndicator extends StatelessWidget {
+ final String assetPath;
+ const _ProgressIndicator({required this.assetPath});
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.only(
+ left: BeamSizes.size4,
+ right: BeamSizes.size8,
+ ),
+ child: SvgPicture.asset(assetPath),
+ );
+ }
+}
+
+class _Content extends StatelessWidget {
+ const _Content();
+
+ @override
+ Widget build(BuildContext context) {
+ final themeData = Theme.of(context);
+
+ return Container(
+ height: MediaQuery.of(context).size.height -
+ BeamSizes.appBarHeight -
+ TobSizes.footerHeight,
+ decoration: BoxDecoration(
+ color: themeData.backgroundColor,
+ border: Border(
+ left: BorderSide(color: themeData.dividerColor),
+ ),
+ ),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Expanded(
+ child: SingleChildScrollView(
+ controller: ScrollController(),
+ child: const FillerText(width: 1000),
+ ),
+ ),
+ const _ContentFooter(),
+ ],
+ ),
+ );
+ }
+}
+
+class _ContentFooter extends StatelessWidget {
+ const _ContentFooter();
+
+ @override
+ Widget build(BuildContext context) {
+ final themeData = Theme.of(context);
+
+ return Container(
+ decoration: BoxDecoration(
+ border: Border(
+ top: BorderSide(color: themeData.dividerColor),
+ ),
+ color:
+ themeData.extension()?.secondaryBackgroundColor,
+ ),
+ width: double.infinity,
+ padding: const EdgeInsets.all(BeamSizes.size20),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ Flexible(
+ child: OutlinedButton(
+ style: OutlinedButton.styleFrom(
+ foregroundColor: themeData.primaryColor,
+ side: BorderSide(color: themeData.primaryColor),
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(
+ Radius.circular(BeamSizes.size4),
+ ),
+ ),
+ ),
+ child: const Text(
+ 'pages.tour.completeUnit',
+ overflow: TextOverflow.ellipsis,
+ ).tr(),
+ onPressed: () {
+ // TODO(nausharipov): complete unit
+ },
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class _NarrowScreenPlayground extends StatelessWidget {
+ const _NarrowScreenPlayground();
+
+ @override
+ Widget build(BuildContext context) {
+ // TODO(alexeyinkin): Even this way the narrow layout breaks, https://github.com/apache/beam/issues/23244
+ return const Center(child: Text('TODO: Playground for narrow screen'));
+ }
+}
diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart
index 2898e1584653..ae799b7e77c4 100644
--- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart
+++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart
@@ -20,20 +20,19 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
+import 'package:playground_components/playground_components.dart';
-import '../../components/complexity.dart';
-import '../../components/page_container.dart';
-import '../../config/theme/colors_provider.dart';
-import '../../constants/assets.dart';
-import '../../constants/colors.dart';
+import '../../components/filler_text.dart';
+import '../../components/scaffold.dart';
import '../../constants/sizes.dart';
+import '../../generated/assets.gen.dart';
class WelcomeScreen extends StatelessWidget {
const WelcomeScreen();
@override
Widget build(BuildContext context) {
- return PageContainer(
+ return TobScaffold(
child: SingleChildScrollView(
child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns
? const _WideWelcome()
@@ -48,16 +47,18 @@ class _WideWelcome extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: const [
- Expanded(
- child: _SdkSelection(),
- ),
- Expanded(
- child: _TourSummary(),
- ),
- ],
+ return IntrinsicHeight(
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: const [
+ Expanded(
+ child: _SdkSelection(),
+ ),
+ Expanded(
+ child: _TourSummary(),
+ ),
+ ],
+ ),
);
}
}
@@ -79,34 +80,35 @@ class _NarrowWelcome extends StatelessWidget {
class _SdkSelection extends StatelessWidget {
const _SdkSelection();
+ static const double _minimalHeight = 900;
+
@override
Widget build(BuildContext context) {
return Container(
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height -
- TobSizes.appBarHeight -
+ BeamSizes.appBarHeight -
TobSizes.footerHeight,
),
- color: ThemeColors.of(context).background,
+ color: Theme.of(context).backgroundColor,
child: Stack(
children: [
Positioned(
bottom: 0,
left: 0,
right: 0,
- // TODO(nausharipov): use flutter_gen after merging
child: Theme.of(context).brightness == Brightness.dark
- ? Image.asset(TobAssets.laptopDark)
- : Image.asset(TobAssets.laptopLight),
+ ? Image.asset(Assets.png.laptopDark.path)
+ : Image.asset(Assets.png.laptopLight.path),
),
- const SizedBox(height: 900),
+ const SizedBox(height: _minimalHeight),
Padding(
padding: const EdgeInsets.fromLTRB(50, 60, 50, 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
_IntroText(),
- SizedBox(height: TobSizes.size32),
+ SizedBox(height: BeamSizes.size32),
_Buttons(),
],
),
@@ -124,7 +126,7 @@ class _TourSummary extends StatelessWidget {
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(
- vertical: TobSizes.size20,
+ vertical: BeamSizes.size20,
horizontal: 27,
),
child: Column(
@@ -135,7 +137,7 @@ class _TourSummary extends StatelessWidget {
isLast: module == _modules.last,
),
)
- .toList(),
+ .toList(growable: false),
),
);
}
@@ -152,6 +154,8 @@ class _TourSummary extends StatelessWidget {
class _IntroText extends StatelessWidget {
const _IntroText();
+ static const double _dividerMaxWidth = 150;
+
@override
Widget build(BuildContext context) {
return Column(
@@ -163,9 +167,9 @@ class _IntroText extends StatelessWidget {
).tr(),
Container(
margin: const EdgeInsets.symmetric(vertical: 32),
- height: 2,
- color: TobColors.grey2,
- constraints: const BoxConstraints(maxWidth: 150),
+ height: BeamSizes.size2,
+ color: BeamColors.grey2,
+ constraints: const BoxConstraints(maxWidth: _dividerMaxWidth),
),
RichText(
text: TextSpan(
@@ -179,7 +183,7 @@ class _IntroText extends StatelessWidget {
style: Theme.of(context)
.textTheme
.bodyLarge!
- .copyWith(color: ThemeColors.of(context).primary),
+ .copyWith(color: Theme.of(context).primaryColor),
recognizer: TapGestureRecognizer()
..onTap = () {
// TODO(nausharipov): sign in
@@ -198,7 +202,7 @@ class _Buttons extends StatelessWidget {
const _Buttons();
void _onSdkChanged(String value) {
- // TODO(nausharipov): select the language
+ // TODO(nausharipov): change sdk
}
@override
@@ -214,13 +218,13 @@ class _Buttons extends StatelessWidget {
onChanged: _onSdkChanged,
),
)
- .toList(),
+ .toList(growable: false),
),
ElevatedButton(
onPressed: () {
// TODO(nausharipov): redirect
},
- child: const Text('pages.welcome.startLearning').tr(),
+ child: const Text('pages.welcome.startTour').tr(),
),
],
);
@@ -246,10 +250,10 @@ class _SdkButton extends StatelessWidget {
padding: const EdgeInsets.only(right: 15, bottom: 10),
child: OutlinedButton(
style: OutlinedButton.styleFrom(
- backgroundColor: ThemeColors.of(context).background,
+ backgroundColor: Theme.of(context).backgroundColor,
side: groupValue == value
? null
- : const BorderSide(color: TobColors.grey1),
+ : const BorderSide(color: BeamColors.grey1),
),
onPressed: () {
onChanged(value);
@@ -293,13 +297,13 @@ class _ModuleHeader extends StatelessWidget {
child: Row(
children: [
Padding(
- padding: const EdgeInsets.all(TobSizes.size4),
+ padding: const EdgeInsets.all(BeamSizes.size4),
child: SvgPicture.asset(
- TobAssets.welcomeProgress0,
- color: ThemeColors.of(context).progressBackgroundColor,
+ Assets.svg.welcomeProgress0,
+ color: BeamColors.grey4,
),
),
- const SizedBox(width: TobSizes.size16),
+ const SizedBox(width: BeamSizes.size16),
Expanded(
child: Text(
title,
@@ -315,7 +319,7 @@ class _ModuleHeader extends StatelessWidget {
'complexity.medium',
style: Theme.of(context).textTheme.headlineSmall,
).tr(),
- const SizedBox(width: TobSizes.size6),
+ const SizedBox(width: BeamSizes.size6),
const ComplexityWidget(complexity: Complexity.medium),
],
),
@@ -332,24 +336,24 @@ class _ModuleBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final themeData = Theme.of(context);
+
return Container(
margin: _moduleLeftMargin,
decoration: BoxDecoration(
border: Border(
left: BorderSide(
- color: ThemeColors.of(context).divider,
+ color: themeData.dividerColor,
),
),
),
padding: _modulePadding,
child: Column(
children: [
- const Text(
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam velit purus, tincidunt id velit vitae, mattis dictum velit. Nunc sit amet nunc at turpis eleifend commodo ac ut libero. Aenean rutrum rutrum nulla ut efficitur. Vestibulum pulvinar eros dictum lectus volutpat dignissim vitae quis nisi. Maecenas sem erat, elementum in euismod ut, interdum ac massa.',
- ),
- const SizedBox(height: TobSizes.size16),
+ const FillerText(width: 20),
+ const SizedBox(height: BeamSizes.size16),
Divider(
- color: ThemeColors.of(context).divider,
+ color: themeData.dividerColor,
),
],
),
@@ -365,9 +369,7 @@ class _LastModuleBody extends StatelessWidget {
return Container(
margin: _moduleLeftMargin,
padding: _modulePadding,
- child: const Text(
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam velit purus, tincidunt id velit vitae, mattis dictum velit. Nunc sit amet nunc at turpis eleifend commodo ac ut libero. Aenean rutrum rutrum nulla ut efficitur. Vestibulum pulvinar eros dictum lectus volutpat dignissim vitae quis nisi. Maecenas sem erat, elementum in euismod ut, interdum ac massa.',
- ),
+ child: const FillerText(width: 20),
);
}
}
diff --git a/learning/tour-of-beam/frontend/pubspec.lock b/learning/tour-of-beam/frontend/pubspec.lock
index b0a898316f4b..c59bb0affd66 100644
--- a/learning/tour-of-beam/frontend/pubspec.lock
+++ b/learning/tour-of-beam/frontend/pubspec.lock
@@ -1,13 +1,34 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
+ _fe_analyzer_shared:
+ dependency: transitive
+ description:
+ name: _fe_analyzer_shared
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "46.0.0"
+ aligned_dialog:
+ dependency: transitive
+ description:
+ name: aligned_dialog
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.0.6"
+ analyzer:
+ dependency: transitive
+ description:
+ name: analyzer
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "4.6.0"
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
- version: "3.1.11"
+ version: "3.3.0"
args:
dependency: transitive
description:
@@ -21,7 +42,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
- version: "2.8.2"
+ version: "2.9.0"
boolean_selector:
dependency: transitive
description:
@@ -29,27 +50,99 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
+ build:
+ dependency: transitive
+ description:
+ name: build
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.3.0"
+ build_config:
+ dependency: transitive
+ description:
+ name: build_config
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.1.0"
+ build_daemon:
+ dependency: transitive
+ description:
+ name: build_daemon
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.1.0"
+ build_resolvers:
+ dependency: transitive
+ description:
+ name: build_resolvers
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.9"
+ build_runner:
+ dependency: "direct dev"
+ description:
+ name: build_runner
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.2.0"
+ build_runner_core:
+ dependency: transitive
+ description:
+ name: build_runner_core
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "7.2.3"
+ built_collection:
+ dependency: transitive
+ description:
+ name: built_collection
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "5.1.1"
+ built_value:
+ dependency: transitive
+ description:
+ name: built_value
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "8.4.1"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
- version: "1.2.0"
- charcode:
+ version: "1.2.1"
+ checked_yaml:
dependency: transitive
description:
- name: charcode
+ name: checked_yaml
url: "https://pub.dartlang.org"
source: hosted
- version: "1.3.1"
+ version: "2.0.1"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.0"
+ version: "1.1.1"
+ code_builder:
+ dependency: transitive
+ description:
+ name: code_builder
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "4.2.0"
+ code_text_field:
+ dependency: "direct main"
+ description:
+ path: "."
+ ref: "9e2c9fe52a69481f038f4b6609e8a0a776429437"
+ resolved-ref: "9e2c9fe52a69481f038f4b6609e8a0a776429437"
+ url: "https://github.com/BertrandBev/code_field.git"
+ source: git
+ version: "1.0.3"
collection:
dependency: transitive
description:
@@ -57,13 +150,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.16.0"
+ color:
+ dependency: transitive
+ description:
+ name: color
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.0.0"
+ convert:
+ dependency: transitive
+ description:
+ name: convert
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.0.2"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
- version: "3.0.1"
+ version: "3.0.2"
csv:
dependency: transitive
description:
@@ -71,6 +178,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.1"
+ dart_style:
+ dependency: transitive
+ description:
+ name: dart_style
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.2.3"
+ dartx:
+ dependency: transitive
+ description:
+ name: dartx
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.1.0"
easy_localization:
dependency: "direct main"
description:
@@ -78,6 +199,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
+ easy_localization_ext:
+ dependency: "direct main"
+ description:
+ name: easy_localization_ext
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.1.1"
easy_localization_loader:
dependency: "direct main"
description:
@@ -92,13 +220,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.2"
+ equatable:
+ dependency: transitive
+ description:
+ name: equatable
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.5"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
- version: "1.3.0"
+ version: "1.3.1"
ffi:
dependency: transitive
description:
@@ -113,6 +248,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.2"
+ fixnum:
+ dependency: transitive
+ description:
+ name: fixnum
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.1"
flutter:
dependency: "direct main"
description: flutter
@@ -123,6 +265,27 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
+ flutter_gen_core:
+ dependency: transitive
+ description:
+ name: flutter_gen_core
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "4.3.0"
+ flutter_gen_runner:
+ dependency: "direct dev"
+ description:
+ name: flutter_gen_runner
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "4.3.0"
+ flutter_highlight:
+ dependency: transitive
+ description:
+ name: flutter_highlight
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.7.0"
flutter_localizations:
dependency: transitive
description: flutter
@@ -145,6 +308,13 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
+ frontend_server_client:
+ dependency: transitive
+ description:
+ name: frontend_server_client
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.3"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
@@ -157,6 +327,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "7.2.0"
+ glob:
+ dependency: transitive
+ description:
+ name: glob
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.0"
google_fonts:
dependency: "direct main"
description:
@@ -164,6 +341,34 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
+ googleapis_auth:
+ dependency: transitive
+ description:
+ name: googleapis_auth
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.3.1"
+ graphs:
+ dependency: transitive
+ description:
+ name: graphs
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.0"
+ grpc:
+ dependency: transitive
+ description:
+ name: grpc
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.0.2"
+ highlight:
+ dependency: transitive
+ description:
+ name: highlight
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.7.0"
http:
dependency: transitive
description:
@@ -171,6 +376,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.4"
+ http2:
+ dependency: transitive
+ description:
+ name: http2
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.0"
+ http_multi_server:
+ dependency: transitive
+ description:
+ name: http_multi_server
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.2.1"
http_parser:
dependency: transitive
description:
@@ -190,6 +409,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.17.0"
+ io:
+ dependency: transitive
+ description:
+ name: io
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.3"
js:
dependency: transitive
description:
@@ -197,27 +423,55 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.4"
+ json_annotation:
+ dependency: transitive
+ description:
+ name: json_annotation
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "4.6.0"
+ linked_scroll_controller:
+ dependency: transitive
+ description:
+ name: linked_scroll_controller
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.2.0"
+ logging:
+ dependency: transitive
+ description:
+ name: logging
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.2"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
- version: "0.12.11"
+ version: "0.12.12"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
- version: "0.1.4"
+ version: "0.1.5"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
- version: "1.7.0"
+ version: "1.8.0"
+ mime:
+ dependency: transitive
+ description:
+ name: mime
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.2"
nested:
dependency: transitive
description:
@@ -225,13 +479,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
+ package_config:
+ dependency: transitive
+ description:
+ name: package_config
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
- version: "1.8.1"
+ version: "1.8.2"
path_drawing:
dependency: transitive
description:
@@ -323,6 +584,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
+ pool:
+ dependency: transitive
+ description:
+ name: pool
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.5.1"
process:
dependency: transitive
description:
@@ -330,6 +598,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.4"
+ protobuf:
+ dependency: transitive
+ description:
+ name: protobuf
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.0"
provider:
dependency: "direct main"
description:
@@ -337,6 +612,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.3"
+ pub_semver:
+ dependency: transitive
+ description:
+ name: pub_semver
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.1"
+ pubspec_parse:
+ dependency: transitive
+ description:
+ name: pubspec_parse
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.2.1"
shared_preferences:
dependency: "direct main"
description:
@@ -393,6 +682,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
+ shelf:
+ dependency: transitive
+ description:
+ name: shelf
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.3.2"
+ shelf_web_socket:
+ dependency: transitive
+ description:
+ name: shelf_web_socket
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.2"
sky_engine:
dependency: transitive
description: flutter
@@ -404,7 +707,7 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
- version: "1.8.2"
+ version: "1.9.0"
stack_trace:
dependency: transitive
description:
@@ -419,34 +722,55 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
+ stream_transform:
+ dependency: transitive
+ description:
+ name: stream_transform
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.0"
+ version: "1.1.1"
sync_http:
dependency: transitive
description:
name: sync_http
url: "https://pub.dartlang.org"
source: hosted
- version: "0.3.0"
+ version: "0.3.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
- version: "1.2.0"
+ version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
- version: "0.4.9"
+ version: "0.4.12"
+ time:
+ dependency: transitive
+ description:
+ name: time
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.2"
+ timing:
+ dependency: transitive
+ description:
+ name: timing
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.0"
total_lints:
dependency: "direct dev"
description:
@@ -460,7 +784,7 @@ packages:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
- version: "1.3.0"
+ version: "1.3.1"
url_launcher:
dependency: "direct main"
description:
@@ -537,7 +861,21 @@ packages:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
- version: "8.2.2"
+ version: "9.0.0"
+ watcher:
+ dependency: transitive
+ description:
+ name: watcher
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.1"
+ web_socket_channel:
+ dependency: transitive
+ description:
+ name: web_socket_channel
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.2.0"
webdriver:
dependency: transitive
description:
@@ -574,5 +912,5 @@ packages:
source: hosted
version: "3.1.1"
sdks:
- dart: ">=2.17.6 <3.0.0"
- flutter: ">=3.0.0"
+ dart: ">=2.18.1 <3.0.0"
+ flutter: ">=3.3.2"
diff --git a/learning/tour-of-beam/frontend/pubspec.yaml b/learning/tour-of-beam/frontend/pubspec.yaml
index 220bfd5e5bce..fb9ee46307d6 100644
--- a/learning/tour-of-beam/frontend/pubspec.yaml
+++ b/learning/tour-of-beam/frontend/pubspec.yaml
@@ -18,29 +18,35 @@
name: tour_of_beam
description: Tour of Beam
-publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+publish_to: 'none'
version: 0.1.0
environment:
- sdk: ">=2.17.6 <3.0.0"
- flutter: ">=3.0.0 <4.0.0"
+ sdk: ">=2.18.1 <3.0.0"
+ flutter: ">=3.3.2"
dependencies:
+ code_text_field:
+ git:
+ url: https://github.com/BertrandBev/code_field.git
+ ref: 9e2c9fe52a69481f038f4b6609e8a0a776429437
easy_localization: ^3.0.1
+ easy_localization_ext: ^0.1.0
easy_localization_loader: ^1.0.0
flutter: { sdk: flutter }
flutter_svg: ^1.0.3
get_it: ^7.2.0
google_fonts: ^3.0.1
- playground_components:
- path: ../../../playground/frontend/playground_components
+ playground_components: { path: ../../../playground/frontend/playground_components }
provider: ^6.0.3
shared_preferences: ^2.0.15
url_launcher: ^6.1.5
url_strategy: ^0.2.0
dev_dependencies:
+ build_runner: ^2.2.0
+ flutter_gen_runner: ^4.3.0
flutter_test: { sdk: flutter }
integration_test: { sdk: flutter }
total_lints: ^2.17.0
@@ -51,3 +57,6 @@ flutter:
- assets/translations/en.yaml
- assets/png/
- assets/svg/
+
+flutter_gen:
+ output: lib/generated/
diff --git a/learning/tour-of-beam/frontend/lib/components/page_container.dart b/learning/tour-of-beam/frontend/test/common/test_screen_wrapper.dart
similarity index 61%
rename from learning/tour-of-beam/frontend/lib/components/page_container.dart
rename to learning/tour-of-beam/frontend/test/common/test_screen_wrapper.dart
index 3500e1739273..8146e336c3df 100644
--- a/learning/tour-of-beam/frontend/lib/components/page_container.dart
+++ b/learning/tour-of-beam/frontend/test/common/test_screen_wrapper.dart
@@ -17,37 +17,23 @@
*/
import 'package:flutter/material.dart';
+import 'package:playground_components/playground_components.dart';
+import 'package:provider/provider.dart';
-import '../constants/sizes.dart';
-import 'footer.dart';
-import 'logo.dart';
-import 'sign_in/sign_in_button.dart';
-import 'toggle_theme_button.dart';
-
-class PageContainer extends StatelessWidget {
+class TestScreenWrapper extends StatelessWidget {
final Widget child;
-
- const PageContainer({
- super.key,
- required this.child,
- });
+ const TestScreenWrapper({required this.child});
@override
Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Logo(),
- actions: const [
- ToggleThemeButton(),
- SignInButton(),
- SizedBox(width: TobSizes.size16),
- ],
- ),
- body: Column(
- children: [
- Expanded(child: child),
- const Footer(),
- ],
+ return ThemeSwitchNotifierProvider(
+ child: Consumer(
+ builder: (context, themeSwitchNotifier, _) {
+ return MaterialApp(
+ theme: kLightTheme,
+ home: child,
+ );
+ },
),
);
}
diff --git a/learning/tour-of-beam/frontend/test/overflow_test.dart b/learning/tour-of-beam/frontend/test/overflow_test.dart
new file mode 100644
index 000000000000..0596b63a61c2
--- /dev/null
+++ b/learning/tour-of-beam/frontend/test/overflow_test.dart
@@ -0,0 +1,34 @@
+/*
+ * 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_test/flutter_test.dart';
+import 'package:tour_of_beam/pages/tour/screen.dart';
+import 'common/test_screen_wrapper.dart';
+
+void main() {
+ testWidgets('WelcomeScreen overflow', (tester) async {
+ tester.binding.window.physicalSizeTestValue = const Size(500, 296);
+ // TODO(nausharipov): fix the failure
+ await tester.pumpWidget(
+ const TestScreenWrapper(
+ child: TourScreen(),
+ ),
+ );
+ });
+}
diff --git a/playground/buf.gen.yaml b/playground/buf.gen.yaml
index bd9b9f3d8309..d04b54a6c5dd 100644
--- a/playground/buf.gen.yaml
+++ b/playground/buf.gen.yaml
@@ -28,5 +28,5 @@ plugins:
- paths=source_relative
- require_unimplemented_servers=false
- name: dart
- out: frontend/lib
- opt: grpc
\ No newline at end of file
+ out: frontend/playground_components/lib/src
+ opt: grpc
diff --git a/playground/frontend/Dockerfile b/playground/frontend/Dockerfile
index 426518693075..2b342adfca1c 100644
--- a/playground/frontend/Dockerfile
+++ b/playground/frontend/Dockerfile
@@ -17,11 +17,11 @@
###############################################################################
FROM debian:11 as build
-ARG FLUTTER_VERSION=3.0.1-stable
+ARG FLUTTER_VERSION=3.3.2
RUN apt-get update && apt-get install -y wget xz-utils git
-RUN wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_$FLUTTER_VERSION.tar.xz &&\
- tar -xf flutter_linux_$FLUTTER_VERSION.tar.xz &&\
+RUN wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_$FLUTTER_VERSION-stable.tar.xz &&\
+ tar -xf flutter_linux_$FLUTTER_VERSION-stable.tar.xz &&\
mv flutter /opt/ &&\
ln -s /opt/flutter/bin/flutter /usr/bin/flutter &&\
ln -s /opt/flutter/bin/dart /usr/bin/dart &&\
@@ -31,9 +31,18 @@ RUN wget https://storage.googleapis.com/flutter_infra_release/releases/stable/li
COPY . /app
WORKDIR /app
-RUN cd /app && flutter build web -v
+
+RUN cd /app/playground_components &&\
+ flutter pub get -v &&\
+ flutter pub run build_runner build -v
+
+RUN cd /app &&\
+ flutter pub get -v &&\
+ flutter pub run build_runner build -v &&\
+ flutter build web -v
+
FROM nginx:1.21.3
COPY --from=build /app/nginx_default.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/build/web/ /usr/share/nginx/html
-RUN cp /usr/share/nginx/html/assets/assets/* /usr/share/nginx/html/assets/
+RUN cp -r /usr/share/nginx/html/assets/assets/* /usr/share/nginx/html/assets/
RUN gzip -kr /usr/share/nginx/html/assets/*
diff --git a/playground/frontend/README.md b/playground/frontend/README.md
index 92eb33628ab2..eb015b48b9ea 100644
--- a/playground/frontend/README.md
+++ b/playground/frontend/README.md
@@ -25,6 +25,18 @@ Beam Playground is an interactive environment to try out Beam transforms and exa
## Getting Started
+Running, debugging, and testing all require this first step that fetches
+dependencies and generates code:
+
+```bash
+cd playground_components
+flutter pub get
+flutter pub run build_runner build
+cd ..
+flutter pub get
+flutter pub run build_runner build
+```
+
### Run
See [playground/README.md](../README.md) for details on requirements and setup.
diff --git a/playground/frontend/assets/theme.svg b/playground/frontend/assets/theme.svg
deleted file mode 100644
index 10d8b3d5c9be..000000000000
--- a/playground/frontend/assets/theme.svg
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
diff --git a/playground/frontend/assets/translations/en.yaml b/playground/frontend/assets/translations/en.yaml
new file mode 100644
index 000000000000..c7d74f96d44f
--- /dev/null
+++ b/playground/frontend/assets/translations/en.yaml
@@ -0,0 +1,21 @@
+# 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.
+
+intents:
+ playground:
+ clearOutput: 'Clear Output'
+ newExample: 'New Example'
diff --git a/playground/frontend/build.gradle b/playground/frontend/build.gradle
index fe8aa85bdf10..5843927fc777 100644
--- a/playground/frontend/build.gradle
+++ b/playground/frontend/build.gradle
@@ -40,26 +40,18 @@ dependencies {
dockerDependency project(path: playgroundJobServerProject, configuration: "shadow")
}
-task removeBuild {
- group = "verification"
- description = "remove build artifacts"
- doLast {
- exec {
- executable("rm")
- args("-r", "build")
- }
- }
-}
-
task analyze {
- dependsOn("pubGet")
- dependsOn("removeBuild")
+ dependsOn("playground_components:generate")
+ dependsOn("generate")
+
group = "verification"
description = "Analyze dart code"
+
doLast {
exec {
+ // Exact paths instead of '.' so it does not go into playground_components
executable("dart")
- args("analyze", ".")
+ args("analyze", "lib", "test")
}
}
}
@@ -80,8 +72,9 @@ task format {
description = "Idiomatically format Dart source code"
doLast {
exec {
+ // Exact paths instead of '.' so it does not go into playground_components
executable("dart")
- args("format", ".")
+ args("format", "lib", "test")
}
}
}
@@ -98,9 +91,12 @@ task run {
}
task test {
- dependsOn("pubGet")
+ dependsOn("playground_components:generate")
+ dependsOn("generate")
+
group = "verification"
description = "flutter test"
+
doLast {
exec {
executable("flutter")
@@ -110,10 +106,37 @@ task test {
}
task precommit {
- dependsOn(":playground:frontend:removeBuild")
- dependsOn(":playground:frontend:pubGet")
- dependsOn(":playground:frontend:analyze")
- dependsOn(":playground:frontend:test")
+ dependsOn("playground_components:precommit")
+
+ dependsOn("analyze")
+ dependsOn("test")
+}
+
+task generate {
+ dependsOn("flutterClean")
+ dependsOn("pubGet")
+
+ group = "build"
+ description = "Generate code"
+
+ doLast {
+ exec {
+ executable("flutter")
+ args("pub", "run", "build_runner", "build", "--delete-conflicting-outputs")
+ }
+ }
+}
+
+task flutterClean {
+ group = "build"
+ description = "Remove build artifacts"
+
+ doLast {
+ exec {
+ executable("flutter")
+ args("clean")
+ }
+ }
}
task copyDockerfileDependencies(type: Copy) {
diff --git a/playground/frontend/lib/components/banner/banner_description.dart b/playground/frontend/lib/components/banner/banner_description.dart
index ab9ccfd51793..34ff3b51cefa 100644
--- a/playground/frontend/lib/components/banner/banner_description.dart
+++ b/playground/frontend/lib/components/banner/banner_description.dart
@@ -18,7 +18,6 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
-import 'package:playground/config/theme.dart';
import 'package:playground/constants/font_weight.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/examples/components/description_popover/description_popover.dart';
@@ -61,10 +60,9 @@ class BannerDescription extends StatelessWidget {
RichText(
text: TextSpan(
children: [
- TextSpan(
+ const TextSpan(
text: kBannerDescription1,
style: TextStyle(
- color: ThemeColors.of(context).textColor,
height: kDescriptionLineHeight,
),
),
@@ -76,10 +74,9 @@ class BannerDescription extends StatelessWidget {
..onTap = () async {
launchUrl(Uri.parse(kBannerUrl));
}),
- TextSpan(
+ const TextSpan(
text: kHyperlinkText,
style: TextStyle(
- color: ThemeColors.of(context).textColor,
height: kDescriptionLineHeight,
),
),
diff --git a/playground/frontend/lib/components/dropdown_button/dropdown_button.dart b/playground/frontend/lib/components/dropdown_button/dropdown_button.dart
index fa89fce72ff0..c2aff6f2f950 100644
--- a/playground/frontend/lib/components/dropdown_button/dropdown_button.dart
+++ b/playground/frontend/lib/components/dropdown_button/dropdown_button.dart
@@ -17,9 +17,9 @@
*/
import 'package:flutter/material.dart';
-import 'package:playground/config/theme.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/utils/dropdown_utils.dart';
+import 'package:playground_components/playground_components.dart';
const int kAnimationDurationInMilliseconds = 80;
const Offset kAnimationBeginOffset = Offset(0.0, -0.02);
@@ -87,10 +87,12 @@ class _AppDropdownButtonState extends State
@override
Widget build(BuildContext context) {
+ final ext = Theme.of(context).extension()!;
+
return Container(
height: kContainerHeight,
decoration: BoxDecoration(
- color: ThemeColors.of(context).dropdownButton,
+ color: ext.fieldBackgroundColor,
borderRadius: BorderRadius.circular(kSmBorderRadius),
),
child: TextButton(
@@ -149,7 +151,7 @@ class _AppDropdownButtonState extends State
height: widget.height,
width: widget.width,
decoration: BoxDecoration(
- color: ThemeColors.of(context).background,
+ color: Theme.of(context).backgroundColor,
borderRadius: BorderRadius.circular(kMdBorderRadius),
),
child: widget.createDropdown(_close),
diff --git a/playground/frontend/lib/components/playground_run_or_cancel_button.dart b/playground/frontend/lib/components/playground_run_or_cancel_button.dart
new file mode 100644
index 000000000000..b555a71a882c
--- /dev/null
+++ b/playground/frontend/lib/components/playground_run_or_cancel_button.dart
@@ -0,0 +1,57 @@
+/*
+ * 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/widgets.dart';
+import 'package:playground_components/playground_components.dart';
+import 'package:provider/provider.dart';
+
+import '../modules/analytics/analytics_service.dart';
+import '../utils/analytics_utils.dart';
+
+class PlaygroundRunOrCancelButton extends StatelessWidget {
+ const PlaygroundRunOrCancelButton();
+
+ @override
+ Widget build(BuildContext context) {
+ return Consumer(
+ builder: (context, playgroundController, child) {
+ final analyticsService = AnalyticsService.get(context);
+ final stopwatch = Stopwatch();
+ final exampleName = getAnalyticsExampleName(playgroundController);
+
+ return RunOrCancelButton(
+ playgroundController: playgroundController,
+ beforeCancel: () {
+ final exampleName = getAnalyticsExampleName(playgroundController);
+ analyticsService.trackClickCancelRunEvent(exampleName);
+ },
+ beforeRun: () {
+ stopwatch.start();
+ analyticsService.trackClickRunEvent(exampleName);
+ },
+ onComplete: () {
+ analyticsService.trackRunTimeEvent(
+ exampleName,
+ stopwatch.elapsedMilliseconds,
+ );
+ },
+ );
+ }
+ );
+ }
+}
diff --git a/playground/frontend/lib/components/toggle_theme_button/toggle_theme_button.dart b/playground/frontend/lib/components/toggle_theme_button/toggle_theme_button.dart
deleted file mode 100644
index 730b5b240b92..000000000000
--- a/playground/frontend/lib/components/toggle_theme_button/toggle_theme_button.dart
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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_gen/gen_l10n/app_localizations.dart';
-import 'package:flutter_svg/flutter_svg.dart';
-import 'package:playground/config/theme.dart';
-import 'package:playground/constants/assets.dart';
-import 'package:playground/constants/sizes.dart';
-import 'package:playground/modules/analytics/analytics_service.dart';
-import 'package:provider/provider.dart';
-
-class ToggleThemeButton extends StatelessWidget {
- const ToggleThemeButton({Key? key}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- final appLocale = AppLocalizations.of(context)!;
-
- return Consumer(builder: (context, notifier, child) {
- final text = notifier.isDarkMode ? appLocale.lightMode : appLocale.darkMode;
-
- return Padding(
- padding: const EdgeInsets.symmetric(
- vertical: kSmSpacing,
- horizontal: kMdSpacing,
- ),
- child: TextButton.icon(
- icon: SvgPicture.asset(kThemeIconAsset),
- label: Text(text),
- onPressed: () {
- notifier.toggleTheme();
- AnalyticsService.get(context)
- .trackClickToggleTheme(!notifier.isDarkMode);
- },
- ),
- );
- });
- }
-}
diff --git a/playground/frontend/lib/config/theme.dart b/playground/frontend/lib/config/theme.dart
deleted file mode 100644
index 62a30f0082b0..000000000000
--- a/playground/frontend/lib/config/theme.dart
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * 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:code_text_field/code_text_field.dart';
-import 'package:flutter/material.dart';
-import 'package:playground/constants/colors.dart';
-import 'package:playground/constants/font_weight.dart';
-import 'package:playground/constants/fonts.dart';
-import 'package:playground/constants/sizes.dart';
-import 'package:playground/modules/editor/components/editor_themes.dart';
-import 'package:provider/provider.dart';
-import 'package:shared_preferences/shared_preferences.dart';
-
-const kThemeMode = 'theme_mode';
-
-class ThemeSwitchNotifier extends ChangeNotifier {
- late SharedPreferences _preferences;
- ThemeMode themeMode = ThemeMode.light;
-
- static const _darkThemeColors = ThemeColors.fromBrightness(isDark: true);
- static const _lightThemeColors = ThemeColors.fromBrightness(isDark: false);
-
- ThemeColors get themeColors {
- switch (themeMode) {
- case ThemeMode.dark:
- return _darkThemeColors;
- default:
- return _lightThemeColors;
- }
- }
-
- final _darkCodeTheme = createTheme(_darkThemeColors);
- final _lightCodeTheme = createTheme(_lightThemeColors);
-
- CodeThemeData get codeTheme {
- switch (themeMode) {
- case ThemeMode.dark:
- return _darkCodeTheme;
- default:
- return _lightCodeTheme;
- }
- }
-
- init() {
- _setPreferences();
- }
-
- _setPreferences() async {
- _preferences = await SharedPreferences.getInstance();
- themeMode = _preferences.getString(kThemeMode) == ThemeMode.dark.toString()
- ? ThemeMode.dark
- : ThemeMode.light;
- notifyListeners();
- }
-
- bool get isDarkMode {
- return themeMode == ThemeMode.dark;
- }
-
- void toggleTheme() {
- themeMode = themeMode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
- _preferences.setString(kThemeMode, themeMode.toString());
- notifyListeners();
- }
-}
-
-class ThemeSwitchNotifierProvider extends StatelessWidget {
- final Widget child;
-
- const ThemeSwitchNotifierProvider({
- super.key,
- required this.child,
- });
-
- @override
- Widget build(BuildContext context) {
- return ChangeNotifierProvider(
- create: (context) => ThemeSwitchNotifier()..init(),
- child: Consumer(
- builder: (context, themeSwitchNotifier, _) => ThemeColorsProvider(
- data: themeSwitchNotifier.themeColors,
- child: child,
- ),
- ),
- );
- }
-}
-
-class ThemeColorsProvider extends StatelessWidget {
- final ThemeColors data;
- final Widget child;
-
- const ThemeColorsProvider({
- super.key,
- required this.data,
- required this.child,
- });
-
- @override
- Widget build(BuildContext context) {
- return Provider.value(
- value: data,
- child: child,
- );
- }
-}
-
-TextTheme createTextTheme(Color textColor) {
- return getBaseFontTheme(
- const TextTheme(
- headline1: TextStyle(),
- headline2: TextStyle(),
- headline3: TextStyle(),
- headline4: TextStyle(),
- headline5: TextStyle(),
- headline6: TextStyle(),
- subtitle1: TextStyle(),
- subtitle2: TextStyle(),
- bodyText1: TextStyle(),
- bodyText2: TextStyle(),
- caption: TextStyle(),
- overline: TextStyle(),
- button: TextStyle(fontWeight: kBoldWeight),
- ).apply(
- bodyColor: textColor,
- displayColor: textColor,
- ),
- );
-}
-
-TextButtonThemeData createTextButtonTheme(Color textColor) {
- return TextButtonThemeData(
- style: TextButton.styleFrom(
- primary: textColor,
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.all(Radius.circular(kLgBorderRadius)),
- ),
- ),
- );
-}
-
-OutlinedButtonThemeData createOutlineButtonTheme(Color textColor) {
- return OutlinedButtonThemeData(
- style: OutlinedButton.styleFrom(
- primary: textColor,
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.all(Radius.circular(kSmBorderRadius)),
- ),
- ),
- );
-}
-
-ElevatedButtonThemeData createElevatedButtonTheme(Color primaryColor) {
- return ElevatedButtonThemeData(
- style: ElevatedButton.styleFrom(primary: primaryColor),
- );
-}
-
-PopupMenuThemeData createPopupMenuTheme() {
- return const PopupMenuThemeData(
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.all(
- Radius.circular(kLgBorderRadius),
- ),
- ),
- );
-}
-
-AppBarTheme createAppBarTheme(Color backgroundColor) {
- return AppBarTheme(
- color: backgroundColor,
- elevation: 1,
- centerTitle: false,
- );
-}
-
-TabBarTheme createTabBarTheme(Color textColor, Color indicatorColor) {
- const labelStyle = TextStyle(fontWeight: kMediumWeight);
- return TabBarTheme(
- unselectedLabelColor: textColor,
- labelColor: textColor,
- labelStyle: labelStyle,
- unselectedLabelStyle: labelStyle,
- indicator: UnderlineTabIndicator(
- borderSide: BorderSide(width: 2.0, 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,
- backgroundColor: kLightPrimaryBackground,
- appBarTheme: createAppBarTheme(kLightSecondaryBackground),
- textTheme: createTextTheme(kLightText),
- popupMenuTheme: createPopupMenuTheme(),
- textButtonTheme: createTextButtonTheme(kLightText),
- outlinedButtonTheme: createOutlineButtonTheme(kLightText),
- elevatedButtonTheme: createElevatedButtonTheme(kLightPrimary),
- tabBarTheme: createTabBarTheme(kLightText, kLightPrimary),
- dialogTheme: createDialogTheme(kLightText),
-);
-
-final kDarkTheme = ThemeData(
- brightness: Brightness.dark,
- primaryColor: kDarkPrimary,
- backgroundColor: kDarkPrimaryBackground,
- appBarTheme: createAppBarTheme(kDarkSecondaryBackground),
- textTheme: createTextTheme(kDarkText),
- popupMenuTheme: createPopupMenuTheme(),
- textButtonTheme: createTextButtonTheme(kDarkText),
- outlinedButtonTheme: createOutlineButtonTheme(kDarkText),
- elevatedButtonTheme: createElevatedButtonTheme(kDarkPrimary),
- tabBarTheme: createTabBarTheme(kDarkText, kDarkPrimary),
- dialogTheme: createDialogTheme(kDarkText),
-);
-
-class ThemeColors {
- final Color? _background;
- final Color? _dropdownButton;
-
- final bool isDark;
-
- static ThemeColors of(BuildContext context, {bool listen = true}) {
- return Provider.of(context, listen: listen);
- }
-
- ThemeColors({
- required this.isDark,
- Color? background,
- Color? dropdownButtonColor,
- }) : _background = background,
- _dropdownButton = dropdownButtonColor;
-
- const ThemeColors.fromBrightness({
- required this.isDark,
- }) : _background = null,
- _dropdownButton = null;
-
- ThemeColors copyWith({
- Color? background,
- Color? dropdownButton,
- }) {
- return ThemeColors(
- isDark: isDark,
- background: background ?? this.background,
- dropdownButtonColor: dropdownButton ?? this.dropdownButton,
- );
- }
-
- Color get dropdownButton =>
- _dropdownButton ?? (isDark ? kDarkGrey : kLightGrey);
-
- Color get divider => isDark ? kDarkGrey : kLightGrey;
-
- Color get lightGreyColor => isDark ? kLightGrey1 : kLightGrey;
-
- Color get primary => isDark ? kLightPrimary : kDarkPrimary;
-
- Color get primaryBackgroundTextColor => Colors.white;
-
- Color get lightGreyBackgroundTextColor => Colors.black;
-
- Color get grey1Color => isDark ? kDarkGrey1 : kLightGrey1;
-
- Color get secondaryBackground =>
- isDark ? kDarkSecondaryBackground : kLightSecondaryBackground;
-
- Color get background =>
- _background ??
- (isDark ? kDarkPrimaryBackground : kLightPrimaryBackground);
-
- Color get code1 => isDark ? kDarkCode2 : kLightCode2;
-
- Color get code2 => isDark ? kDarkCode1 : kLightCode1;
-
- Color get codeComment => isDark ? kDarkCodeComment : kLightCodeComment;
-
- Color get textColor => isDark ? kDarkText : kLightText;
-}
diff --git a/playground/frontend/lib/constants/sizes.dart b/playground/frontend/lib/constants/sizes.dart
index 3d895aae285d..c4515a5e3dc1 100644
--- a/playground/frontend/lib/constants/sizes.dart
+++ b/playground/frontend/lib/constants/sizes.dart
@@ -25,23 +25,17 @@ const double kXlSpacing = 16.0;
const double kXxlSpacing = 36.0;
// sizes
-const kHeaderButtonHeight = 46.0;
-const kRunButtonWidth = 150.0;
const kButtonHeight = 40.0;
const kIconButtonSplashRadius = 24.0;
-const kFooterHeight = 32.0;
// border radius
const double kSmBorderRadius = 4.0;
const double kMdBorderRadius = 6.0;
-const double kLgBorderRadius = 8.0;
-const double kXlBorderRadius = 28.0;
// elevation
const double kElevation = 2;
// icon sizes
-const double kIconSizeXs = 8.0;
const double kIconSizeSm = 16.0;
const double kIconSizeMd = 24.0;
const double kIconSizeLg = 32.0;
@@ -52,16 +46,8 @@ const double kCursorSize = 1.0;
// container size
const double kContainerHeight = 40.0;
-const double kCaptionFontSize = 10.0;
-const double kCodeFontSize = 14.0;
const double kLabelFontSize = 16.0;
-const double kHintFontSize = 16.0;
const double kTitleFontSize = 18.0;
//divider size
const double kDividerHeight = 1.0;
-const double kLgDividerHeight = 2.0;
-
-//loading indicator size
-const double kMdLoadingIndicatorSize = 40.0;
-const double kLgLoadingIndicatorSize = 50.0;
diff --git a/playground/frontend/lib/l10n/app_en.arb b/playground/frontend/lib/l10n/app_en.arb
index 48a3a8675b82..538df437994a 100644
--- a/playground/frontend/lib/l10n/app_en.arb
+++ b/playground/frontend/lib/l10n/app_en.arb
@@ -7,14 +7,6 @@
"@darkMode": {
"description": "Title for a theme switch"
},
- "newExample": "New Example",
- "@newExample": {
- "description": "Title for the New Example button"
- },
- "reset": "Reset",
- "@reset": {
- "description": "Title for the reset button"
- },
"run": "Run",
"@run": {
"description": "Title for the run button"
@@ -143,10 +135,6 @@
"@reportIssue": {
"description": "Title for the Report issue in GitHub button"
},
- "codeTextArea": "Code Text Area",
- "@codeTextArea": {
- "description": "Title for the Code text area semantics"
- },
"bottom": "Bottom",
"@bottom": {
"description": "Part of the output placements semantics label"
@@ -159,10 +147,6 @@
"@left": {
"description": "Part of the output placements semantics label"
},
- "clearOutput": "Clear Output",
- "@clearOutput": {
- "description": "Title for the Clear Output shortcut row"
- },
"pipelineOptions": "Pipeline Options",
"@pipelineOptions": {
"description": "Title for the Pipeline Options"
diff --git a/playground/frontend/lib/l10n/l10n.dart b/playground/frontend/lib/l10n/l10n.dart
index cd63ec779909..9f7e197317e4 100644
--- a/playground/frontend/lib/l10n/l10n.dart
+++ b/playground/frontend/lib/l10n/l10n.dart
@@ -16,10 +16,12 @@
* limitations under the License.
*/
-import 'package:flutter/material.dart';
+import 'dart:ui';
class L10n {
+ static const en = Locale('en');
+
static const locales = [
- Locale('en'),
+ en,
];
}
diff --git a/playground/frontend/lib/main.dart b/playground/frontend/lib/main.dart
index 2e57fc49a120..0c36af3e7bcf 100644
--- a/playground/frontend/lib/main.dart
+++ b/playground/frontend/lib/main.dart
@@ -17,15 +17,34 @@
*/
import 'package:akvelon_flutter_issue_106664_workaround/akvelon_flutter_issue_106664_workaround.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:easy_localization_ext/easy_localization_ext.dart';
+import 'package:easy_localization_loader/easy_localization_loader.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl_browser.dart';
-import 'package:playground/configure_nonweb.dart'
-if (dart.library.html) 'package:playground/configure_web.dart';
import 'package:playground/playground_app.dart';
+import 'package:playground_components/playground_components.dart';
+import 'package:url_strategy/url_strategy.dart';
-void main() {
+import 'l10n/l10n.dart';
+
+void main() async {
FlutterIssue106664Workaround.instance.apply();
- findSystemLocale();
- configureApp();
- runApp(const PlaygroundApp());
+ setPathUrlStrategy();
+ await EasyLocalization.ensureInitialized();
+
+ await findSystemLocale();
+ runApp(
+ EasyLocalization(
+ supportedLocales: L10n.locales,
+ startLocale: L10n.en,
+ fallbackLocale: L10n.en,
+ path: 'assets/translations',
+ assetLoader: MultiAssetLoader([
+ PlaygroundComponents.translationLoader,
+ YamlAssetLoader(),
+ ]),
+ child: const PlaygroundApp(),
+ ),
+ );
}
diff --git a/playground/frontend/lib/modules/actions/components/new_example_action.dart b/playground/frontend/lib/modules/actions/components/new_example_action.dart
index 332b4beba397..594492987c11 100644
--- a/playground/frontend/lib/modules/actions/components/new_example_action.dart
+++ b/playground/frontend/lib/modules/actions/components/new_example_action.dart
@@ -16,13 +16,11 @@
* limitations under the License.
*/
+import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-import 'package:playground/config/theme.dart';
-import 'package:playground/modules/actions/components/header_icon_button.dart';
import 'package:playground/modules/analytics/analytics_service.dart';
-import 'package:playground/modules/shortcuts/components/shortcut_tooltip.dart';
import 'package:playground/modules/shortcuts/constants/global_shortcuts.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:url_launcher/url_launcher.dart';
class NewExampleAction extends StatelessWidget {
@@ -35,9 +33,9 @@ class NewExampleAction extends StatelessWidget {
child: HeaderIconButton(
icon: Icon(
Icons.add_circle_outline,
- color: ThemeColors.of(context).grey1Color,
+ color: Theme.of(context).extension()?.iconColor,
),
- label: AppLocalizations.of(context)!.newExample,
+ label: 'intents.playground.newExample'.tr(),
onPressed: () {
launchUrl(Uri.parse('/'));
AnalyticsService.get(context).trackClickNewExample();
diff --git a/playground/frontend/lib/modules/actions/components/reset_action.dart b/playground/frontend/lib/modules/actions/components/reset_action.dart
index 533bdec2d1c4..a0e111996322 100644
--- a/playground/frontend/lib/modules/actions/components/reset_action.dart
+++ b/playground/frontend/lib/modules/actions/components/reset_action.dart
@@ -17,33 +17,21 @@
*/
import 'package:flutter/material.dart';
-import 'package:flutter_svg/flutter_svg.dart';
-import 'package:playground/config/theme.dart';
-import 'package:playground/constants/assets.dart';
-import 'package:playground/modules/actions/components/header_icon_button.dart';
import 'package:playground/modules/analytics/analytics_service.dart';
-import 'package:playground/modules/shortcuts/components/shortcut_tooltip.dart';
-import 'package:playground/modules/shortcuts/constants/global_shortcuts.dart';
-import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:playground_components/playground_components.dart';
+import 'package:provider/provider.dart';
class ResetAction extends StatelessWidget {
- final VoidCallback reset;
-
- const ResetAction({Key? key, required this.reset}) : super(key: key);
+ const ResetAction();
@override
Widget build(BuildContext context) {
- return ShortcutTooltip(
- shortcut: kResetShortcut,
- child: HeaderIconButton(
- icon: SvgPicture.asset(
- kResetIconAsset,
- color: ThemeColors.of(context).grey1Color,
- ),
- label: AppLocalizations.of(context)!.reset,
- onPressed: () {
- reset();
- AnalyticsService.get(context).trackReset();
+ final analyticsService = AnalyticsService.get(context);
+ return Consumer(
+ builder: (context, playgroundController, child) => ResetButton(
+ playgroundController: playgroundController,
+ beforeReset: () {
+ analyticsService.trackReset();
},
),
);
diff --git a/playground/frontend/lib/modules/analytics/analytics_service.dart b/playground/frontend/lib/modules/analytics/analytics_service.dart
index 6571a4898d44..0416e7dcc520 100644
--- a/playground/frontend/lib/modules/analytics/analytics_service.dart
+++ b/playground/frontend/lib/modules/analytics/analytics_service.dart
@@ -17,8 +17,7 @@
*/
import 'package:flutter/widgets.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
-import 'package:playground/modules/sdk/models/sdk.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:provider/provider.dart';
abstract class AnalyticsService {
@@ -26,8 +25,8 @@ abstract class AnalyticsService {
return Provider.of(context, listen: false);
}
- void trackSelectSdk(SDK? oldSdk, SDK newSdk);
- void trackSelectExample(ExampleModel newExample);
+ void trackSelectSdk(Sdk? oldSdk, Sdk newSdk);
+ void trackSelectExample(ExampleBase newExample);
void trackClickNewExample();
void trackReset();
void trackClickToggleTheme(bool isDark);
diff --git a/playground/frontend/lib/modules/analytics/google_analytics_service.dart b/playground/frontend/lib/modules/analytics/google_analytics_service.dart
index d9eaf2e6f120..7b083b3bc25e 100644
--- a/playground/frontend/lib/modules/analytics/google_analytics_service.dart
+++ b/playground/frontend/lib/modules/analytics/google_analytics_service.dart
@@ -19,24 +19,23 @@
import 'package:playground/config.g.dart';
import 'package:playground/modules/analytics/analytics_events.dart';
import 'package:playground/modules/analytics/analytics_service.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
-import 'package:playground/modules/sdk/models/sdk.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:usage/usage_html.dart';
class GoogleAnalyticsService implements AnalyticsService {
final _analytics = AnalyticsHtml(kAnalyticsUA, 'beam', '1.0');
@override
- void trackSelectSdk(SDK? oldSdk, SDK newSdk) {
+ void trackSelectSdk(Sdk? oldSdk, Sdk newSdk) {
safeSendEvent(
kSdkCategory,
kSelectSdkEvent,
- label: '${oldSdk?.displayName}_${newSdk.displayName}',
+ label: '${oldSdk?.title}_${newSdk.title}',
);
}
@override
- void trackSelectExample(ExampleModel newExample) {
+ void trackSelectExample(ExampleBase newExample) {
safeSendEvent(
kExampleCategory,
kSelectExampleEvent,
diff --git a/playground/frontend/lib/modules/editor/components/editor_themes.dart b/playground/frontend/lib/modules/editor/components/editor_themes.dart
deleted file mode 100644
index 42c68905f962..000000000000
--- a/playground/frontend/lib/modules/editor/components/editor_themes.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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:code_text_field/code_text_field.dart';
-import 'package:flutter/material.dart';
-import 'package:playground/config/theme.dart';
-
-CodeThemeData createTheme(ThemeColors colors) {
- return CodeThemeData(
- styles: _createThemeStyles(colors),
- );
-}
-
-Map _createThemeStyles(ThemeColors colors) {
- return {
- 'root': TextStyle(
- backgroundColor: colors.background,
- color: colors.textColor,
- ),
- 'comment': TextStyle(color: colors.codeComment),
- 'quote': TextStyle(color: colors.code2),
- 'variable': TextStyle(color: colors.code2),
- 'keyword': TextStyle(color: colors.code2),
- 'selector-tag': TextStyle(color: colors.code2),
- 'built_in': TextStyle(color: colors.code2),
- 'name': TextStyle(color: colors.code2),
- 'tag': TextStyle(color: colors.code2),
- 'string': TextStyle(color: colors.code1),
- 'title': TextStyle(color: colors.code1),
- 'section': TextStyle(color: colors.code1),
- 'attribute': TextStyle(color: colors.code1),
- 'literal': TextStyle(color: colors.code1),
- 'template-tag': TextStyle(color: colors.code1),
- 'template-variable': TextStyle(color: colors.code1),
- 'type': TextStyle(color: colors.code1),
- 'addition': TextStyle(color: colors.code1),
- 'deletion': TextStyle(color: colors.code2),
- 'selector-attr': TextStyle(color: colors.code2),
- 'selector-pseudo': TextStyle(color: colors.code2),
- 'meta': TextStyle(color: colors.code2),
- 'doctag': TextStyle(color: colors.codeComment),
- 'attr': TextStyle(color: colors.primary),
- 'symbol': TextStyle(color: colors.code2),
- 'bullet': TextStyle(color: colors.code2),
- 'link': TextStyle(color: colors.code2),
- 'emphasis': const TextStyle(fontStyle: FontStyle.italic),
- 'strong': const TextStyle(fontWeight: FontWeight.bold),
- };
-}
diff --git a/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_dropdown_body.dart b/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_dropdown_body.dart
index fd1d6c9eedaa..0b8cd5836b4b 100644
--- a/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_dropdown_body.dart
+++ b/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_dropdown_body.dart
@@ -24,7 +24,7 @@ import 'package:playground/modules/editor/components/pipeline_options_dropdown/p
import 'package:playground/modules/editor/components/pipeline_options_dropdown/pipeline_options_dropdown_input.dart';
import 'package:playground/modules/editor/components/pipeline_options_dropdown/pipeline_options_dropdown_separator.dart';
import 'package:playground/modules/editor/components/pipeline_options_dropdown/pipeline_options_form.dart';
-import 'package:playground/modules/editor/parsers/run_options_parser.dart';
+import 'package:playground_components/playground_components.dart';
const kOptionsTabIndex = 0;
const kRawTabIndex = 1;
diff --git a/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_dropdown_separator.dart b/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_dropdown_separator.dart
index 17070dd84f16..78f8b0d7c34c 100644
--- a/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_dropdown_separator.dart
+++ b/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_dropdown_separator.dart
@@ -17,8 +17,8 @@
*/
import 'package:flutter/material.dart';
-import 'package:playground/config/theme.dart';
import 'package:playground/constants/sizes.dart';
+import 'package:playground_components/playground_components.dart';
class PipelineOptionsDropdownSeparator extends StatelessWidget {
const PipelineOptionsDropdownSeparator({Key? key}) : super(key: key);
@@ -28,7 +28,7 @@ class PipelineOptionsDropdownSeparator extends StatelessWidget {
return Container(
height: kDividerHeight,
decoration: BoxDecoration(
- color: ThemeColors.of(context).lightGreyColor,
+ color: Theme.of(context).extension()?.borderColor,
),
);
}
diff --git a/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_form.dart b/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_form.dart
index a7f2eabf87e3..6aa41c0c3cdf 100644
--- a/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_form.dart
+++ b/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_form.dart
@@ -16,10 +16,9 @@
* limitations under the License.
*/
+import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-import 'package:collection/collection.dart';
-import 'package:playground/config/theme.dart';
import 'package:playground/constants/colors.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/editor/components/pipeline_options_dropdown/pipeline_option_controller.dart';
@@ -81,7 +80,7 @@ class PipelineOptionsForm extends StatelessWidget {
Icons.delete_outlined,
color: kLightPrimary,
),
- color: ThemeColors.of(context).grey1Color,
+ color: Theme.of(context).dividerColor,
onPressed: () => onDelete(index),
),
),
diff --git a/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_text_field.dart b/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_text_field.dart
index 2c1187365288..d4202b125697 100644
--- a/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_text_field.dart
+++ b/playground/frontend/lib/modules/editor/components/pipeline_options_dropdown/pipeline_options_text_field.dart
@@ -17,8 +17,8 @@
*/
import 'package:flutter/material.dart';
-import 'package:playground/config/theme.dart';
import 'package:playground/constants/sizes.dart';
+import 'package:playground_components/playground_components.dart';
class PipelineOptionsTextField extends StatelessWidget {
final TextEditingController controller;
@@ -32,6 +32,9 @@ class PipelineOptionsTextField extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final themeData = Theme.of(context);
+ final ext = themeData.extension()!;
+
return Container(
margin: const EdgeInsets.only(
top: kMdSpacing,
@@ -48,16 +51,15 @@ class PipelineOptionsTextField extends StatelessWidget {
controller: controller,
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(kMdSpacing),
- border: _getInputBorder(ThemeColors.of(context).lightGreyColor),
- focusedBorder: _getInputBorder(ThemeColors.of(context).primary),
+ border: _getInputBorder(ext.borderColor),
+ focusedBorder: _getInputBorder(themeData.primaryColor),
),
- cursorColor: ThemeColors.of(context).textColor,
),
),
);
}
- _getInputBorder(Color color) {
+ OutlineInputBorder _getInputBorder(Color color) {
return OutlineInputBorder(
borderSide: BorderSide(color: color),
borderRadius: BorderRadius.circular(kMdBorderRadius),
diff --git a/playground/frontend/lib/modules/editor/components/share_dropdown/link_text_field.dart b/playground/frontend/lib/modules/editor/components/share_dropdown/link_text_field.dart
index 9708a88208a0..67430514e5a3 100644
--- a/playground/frontend/lib/modules/editor/components/share_dropdown/link_text_field.dart
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/link_text_field.dart
@@ -18,9 +18,9 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
-import 'package:playground/config/theme.dart';
import 'package:playground/constants/font_weight.dart';
import 'package:playground/constants/sizes.dart';
+import 'package:playground_components/playground_components.dart';
const _kTextFieldMaxHeight = 45.0;
@@ -45,9 +45,11 @@ class _LinkTextFieldState extends State {
@override
Widget build(BuildContext context) {
+ final themeData = Theme.of(context);
+
return Container(
decoration: BoxDecoration(
- color: ThemeColors.of(context).dropdownButton,
+ color: themeData.extension()?.borderColor,
borderRadius: BorderRadius.circular(kSmBorderRadius),
),
child: Container(
@@ -66,7 +68,7 @@ class _LinkTextFieldState extends State {
style: TextStyle(
fontSize: kLabelFontSize,
fontWeight: kNormalWeight,
- color: ThemeColors.of(context).primary,
+ color: themeData.primaryColor,
),
),
),
diff --git a/playground/frontend/lib/modules/editor/components/share_dropdown/share_button.dart b/playground/frontend/lib/modules/editor/components/share_dropdown/share_button.dart
index 9355934e7186..f0f6026ea693 100644
--- a/playground/frontend/lib/modules/editor/components/share_dropdown/share_button.dart
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_button.dart
@@ -19,8 +19,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:playground/components/dropdown_button/dropdown_button.dart';
-import 'package:playground/config/theme.dart';
import 'package:playground/modules/editor/components/share_dropdown/share_dropdown_body.dart';
+import 'package:playground_components/playground_components.dart';
const _kShareDropdownHeight = 140.0;
const _kShareDropdownWidth = 460.0;
@@ -31,22 +31,28 @@ class ShareButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final parentThemeData = Theme.of(context);
+ final ext = parentThemeData.extension()!;
final appLocale = AppLocalizations.of(context)!;
- final parentThemeData = ThemeColors.of(context);
final themeData = parentThemeData.copyWith(
- background: parentThemeData.secondaryBackground,
- dropdownButton: parentThemeData.primary.withOpacity(_kButtonColorOpacity),
+ backgroundColor: ext.secondaryBackgroundColor,
+ extensions: {
+ ext.copyWith(
+ fieldBackgroundColor:
+ parentThemeData.primaryColor.withOpacity(_kButtonColorOpacity),
+ ),
+ },
);
- return ThemeColorsProvider(
+ return Theme(
data: themeData,
child: AppDropdownButton(
buttonText: Text(appLocale.shareMyCode),
showArrow: false,
leading: Icon(
Icons.share_outlined,
- color: ThemeColors.of(context).primary,
+ color: themeData.primaryColor,
),
height: _kShareDropdownHeight,
width: _kShareDropdownWidth,
diff --git a/playground/frontend/lib/modules/editor/components/share_dropdown/share_dropdown_body.dart b/playground/frontend/lib/modules/editor/components/share_dropdown/share_dropdown_body.dart
index 68a208373671..18366335fee7 100644
--- a/playground/frontend/lib/modules/editor/components/share_dropdown/share_dropdown_body.dart
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_dropdown_body.dart
@@ -19,7 +19,7 @@
import 'package:flutter/material.dart';
import 'package:playground/modules/editor/components/share_dropdown/share_tabs/share_tabs.dart';
import 'package:playground/modules/editor/components/share_dropdown/share_tabs_headers.dart';
-import 'package:playground/modules/output/components/output_header/tab_header.dart';
+import 'package:playground_components/playground_components.dart';
const _kTabsCount = 2;
diff --git a/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/share_tabs.dart b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/share_tabs.dart
index 8c2e72948ae0..45d5b82cd005 100644
--- a/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/share_tabs.dart
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/share_tabs.dart
@@ -19,7 +19,7 @@
import 'package:flutter/material.dart';
import 'package:playground/modules/editor/components/share_dropdown/share_tabs/example_share_tabs.dart';
import 'package:playground/modules/editor/components/share_dropdown/share_tabs/snippet_save_and_share_tabs.dart';
-import 'package:playground/pages/playground/states/playground_state.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:provider/provider.dart';
class ShareTabs extends StatelessWidget {
@@ -34,17 +34,17 @@ class ShareTabs extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).backgroundColor,
- child: Consumer(
- builder: (context, playgroundState, _) {
- if (playgroundState.isExampleChanged) {
+ child: Consumer(
+ builder: (context, playgroundController, _) {
+ if (playgroundController.isExampleChanged) {
return SnippetSaveAndShareTabs(
- playgroundState: playgroundState,
+ playgroundController: playgroundController,
tabController: tabController,
);
}
return ExampleShareTabs(
- examplePath: playgroundState.selectedExample!.path,
+ examplePath: playgroundController.selectedExample!.path,
tabController: tabController,
);
},
diff --git a/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/snippet_save_and_share_tabs.dart b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/snippet_save_and_share_tabs.dart
index ddd1bbb0f536..050725de8d92 100644
--- a/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/snippet_save_and_share_tabs.dart
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/snippet_save_and_share_tabs.dart
@@ -17,28 +17,26 @@
*/
import 'package:flutter/material.dart';
-import 'package:playground/components/loading_indicator/loading_indicator.dart';
-import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/editor/components/share_dropdown/share_tabs/example_share_tabs.dart';
-import 'package:playground/pages/playground/states/playground_state.dart';
+import 'package:playground_components/playground_components.dart';
class SnippetSaveAndShareTabs extends StatelessWidget {
- final PlaygroundState playgroundState;
+ final PlaygroundController playgroundController;
final TabController tabController;
const SnippetSaveAndShareTabs({
super.key,
- required this.playgroundState,
+ required this.playgroundController,
required this.tabController,
});
@override
Widget build(BuildContext context) {
return FutureBuilder(
- future: playgroundState.getSnippetId(),
+ future: playgroundController.getSnippetId(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
- return const LoadingIndicator(size: kLgLoadingIndicatorSize);
+ return const LoadingIndicator();
}
return ExampleShareTabs(
diff --git a/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs_headers.dart b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs_headers.dart
index 4d80b4309bd2..1d528a0b228e 100644
--- a/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs_headers.dart
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs_headers.dart
@@ -17,7 +17,7 @@
*/
import 'package:flutter/material.dart';
-import 'package:playground/pages/playground/states/playground_state.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -35,17 +35,19 @@ class ShareTabsHeaders extends StatelessWidget {
Widget build(BuildContext context) {
final appLocale = AppLocalizations.of(context)!;
- return Consumer(builder: (context, state, child) {
- return SizedBox(
- width: _width,
- child: TabBar(
- controller: tabController,
- tabs: [
- Text(appLocale.link),
- Text(appLocale.embed),
- ],
- ),
- );
- });
+ return Consumer(
+ builder: (context, controller, child) {
+ return SizedBox(
+ width: _width,
+ child: TabBar(
+ controller: tabController,
+ tabs: [
+ Text(appLocale.link),
+ Text(appLocale.embed),
+ ],
+ ),
+ );
+ },
+ );
}
}
diff --git a/playground/frontend/lib/modules/editor/repository/code_repository/code_client/grpc_code_client.dart b/playground/frontend/lib/modules/editor/repository/code_repository/code_client/grpc_code_client.dart
deleted file mode 100644
index 6ec86f1826b2..000000000000
--- a/playground/frontend/lib/modules/editor/repository/code_repository/code_client/grpc_code_client.dart
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * 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:grpc/grpc_web.dart';
-import 'package:playground/api/iis_workaround_channel.dart';
-import 'package:playground/api/v1/api.pbgrpc.dart' as grpc;
-import 'package:playground/config.g.dart';
-import 'package:playground/modules/editor/parsers/run_options_parser.dart';
-import 'package:playground/modules/editor/repository/code_repository/code_client/check_status_response.dart';
-import 'package:playground/modules/editor/repository/code_repository/code_client/code_client.dart';
-import 'package:playground/modules/editor/repository/code_repository/code_client/output_response.dart';
-import 'package:playground/modules/editor/repository/code_repository/code_client/run_code_response.dart';
-import 'package:playground/modules/editor/repository/code_repository/run_code_error.dart';
-import 'package:playground/modules/editor/repository/code_repository/run_code_request.dart';
-import 'package:playground/modules/editor/repository/code_repository/run_code_result.dart';
-import 'package:playground/modules/sdk/models/sdk.dart';
-import 'package:playground/utils/replace_incorrect_symbols.dart';
-
-const kGeneralError = 'Failed to execute code';
-
-class GrpcCodeClient implements CodeClient {
- late final grpc.PlaygroundServiceClient _defaultClient;
-
- GrpcCodeClient() {
- final channel = IisWorkaroundChannel.xhr(
- Uri.parse(kApiClientURL),
- );
- _defaultClient = grpc.PlaygroundServiceClient(channel);
- }
-
- @override
- Future runCode(RunCodeRequestWrapper request) {
- return _runSafely(() => _createRunCodeClient(request.sdk)
- .runCode(_toGrpcRequest(request))
- .then((response) => RunCodeResponse(response.pipelineUuid)));
- }
-
- @override
- Future cancelExecution(String pipelineUuid) {
- return _runSafely(() =>
- _defaultClient.cancel(grpc.CancelRequest(pipelineUuid: pipelineUuid)));
- }
-
- @override
- Future checkStatus(
- String pipelineUuid,
- RunCodeRequestWrapper request,
- ) {
- return _runSafely(() => _defaultClient
- .checkStatus(grpc.CheckStatusRequest(pipelineUuid: pipelineUuid))
- .then(
- (response) => CheckStatusResponse(_toClientStatus(response.status)),
- ));
- }
-
- @override
- Future getCompileOutput(
- String pipelineUuid,
- RunCodeRequestWrapper request,
- ) {
- return _runSafely(() => _defaultClient
- .getCompileOutput(
- grpc.GetCompileOutputRequest(pipelineUuid: pipelineUuid),
- )
- .then((response) => _toOutputResponse(response.output)));
- }
-
- @override
- Future getRunOutput(
- String pipelineUuid,
- RunCodeRequestWrapper request,
- ) {
- return _runSafely(() => _defaultClient
- .getRunOutput(grpc.GetRunOutputRequest(pipelineUuid: pipelineUuid))
- .then((response) => _toOutputResponse(response.output))
- .catchError((err) {
- print(err);
- return _toOutputResponse('');
- }));
- }
-
- @override
- Future getLogOutput(
- String pipelineUuid,
- RunCodeRequestWrapper request,
- ) {
- return _runSafely(() => _defaultClient
- .getLogs(grpc.GetLogsRequest(pipelineUuid: pipelineUuid))
- .then((response) => _toOutputResponse(response.output))
- .catchError((err) {
- print(err);
- return _toOutputResponse('');
- }));
- }
-
- @override
- Future getRunErrorOutput(
- String pipelineUuid,
- RunCodeRequestWrapper request,
- ) {
- return _runSafely(() => _defaultClient
- .getRunError(grpc.GetRunErrorRequest(pipelineUuid: pipelineUuid))
- .then((response) => _toOutputResponse(response.output)));
- }
-
- @override
- Future getValidationErrorOutput(
- String pipelineUuid,
- RunCodeRequestWrapper request,
- ) {
- return _runSafely(() => _defaultClient
- .getValidationOutput(
- grpc.GetValidationOutputRequest(pipelineUuid: pipelineUuid))
- .then((response) => _toOutputResponse(response.output)));
- }
-
- @override
- Future getPreparationErrorOutput(
- String pipelineUuid,
- RunCodeRequestWrapper request,
- ) {
- return _runSafely(() => _defaultClient
- .getPreparationOutput(
- grpc.GetPreparationOutputRequest(pipelineUuid: pipelineUuid))
- .then((response) => _toOutputResponse(response.output)));
- }
-
- @override
- Future getGraphOutput(
- String pipelineUuid,
- RunCodeRequestWrapper request,
- ) {
- return _runSafely(() => _defaultClient
- .getGraph(grpc.GetGraphRequest(pipelineUuid: pipelineUuid))
- .then((response) => OutputResponse(response.graph))
- .catchError((err) {
- print(err);
- return _toOutputResponse('');
- }));
- }
-
- Future _runSafely(Future Function() invoke) async {
- try {
- return await invoke();
- } on GrpcError catch (error) {
- throw RunCodeError(error.message);
- } on Exception catch (_) {
- throw RunCodeError(null);
- }
- }
-
- /// Run Code request should use different urls for each sdk
- /// instead of the default one, because we need to code
- /// sdk services for it
- grpc.PlaygroundServiceClient _createRunCodeClient(SDK? sdk) {
- String apiClientURL = kApiClientURL;
- if (sdk != null) {
- apiClientURL = sdk.getRoute;
- }
- IisWorkaroundChannel channel = IisWorkaroundChannel.xhr(
- Uri.parse(apiClientURL),
- );
- return grpc.PlaygroundServiceClient(channel);
- }
-
- grpc.RunCodeRequest _toGrpcRequest(RunCodeRequestWrapper request) {
- return grpc.RunCodeRequest()
- ..code = request.code
- ..sdk = _getGrpcSdk(request.sdk)
- ..pipelineOptions = pipelineOptionsToString(request.pipelineOptions);
- }
-
- grpc.Sdk _getGrpcSdk(SDK sdk) {
- switch (sdk) {
- case SDK.java:
- return grpc.Sdk.SDK_JAVA;
- case SDK.go:
- return grpc.Sdk.SDK_GO;
- case SDK.python:
- return grpc.Sdk.SDK_PYTHON;
- case SDK.scio:
- return grpc.Sdk.SDK_SCIO;
- }
- }
-
- RunCodeStatus _toClientStatus(grpc.Status status) {
- switch (status) {
- case grpc.Status.STATUS_UNSPECIFIED:
- return RunCodeStatus.unspecified;
- case grpc.Status.STATUS_VALIDATING:
- case grpc.Status.STATUS_PREPARING:
- return RunCodeStatus.preparation;
- case grpc.Status.STATUS_COMPILING:
- return RunCodeStatus.compiling;
- case grpc.Status.STATUS_EXECUTING:
- return RunCodeStatus.executing;
- case grpc.Status.STATUS_CANCELED:
- case grpc.Status.STATUS_FINISHED:
- return RunCodeStatus.finished;
- case grpc.Status.STATUS_COMPILE_ERROR:
- return RunCodeStatus.compileError;
- case grpc.Status.STATUS_RUN_TIMEOUT:
- return RunCodeStatus.timeout;
- case grpc.Status.STATUS_RUN_ERROR:
- return RunCodeStatus.runError;
- case grpc.Status.STATUS_VALIDATION_ERROR:
- return RunCodeStatus.validationError;
- case grpc.Status.STATUS_PREPARATION_ERROR:
- return RunCodeStatus.preparationError;
- case grpc.Status.STATUS_ERROR:
- return RunCodeStatus.unknownError;
- }
- return RunCodeStatus.unspecified;
- }
-
- OutputResponse _toOutputResponse(String response) {
- return OutputResponse(replaceIncorrectSymbols(response));
- }
-}
diff --git a/playground/frontend/lib/modules/examples/components/description_popover/description_popover.dart b/playground/frontend/lib/modules/examples/components/description_popover/description_popover.dart
index a438aac5baed..e368973cb64b 100644
--- a/playground/frontend/lib/modules/examples/components/description_popover/description_popover.dart
+++ b/playground/frontend/lib/modules/examples/components/description_popover/description_popover.dart
@@ -22,13 +22,13 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:playground/constants/assets.dart';
import 'package:playground/constants/font_weight.dart';
import 'package:playground/constants/sizes.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:url_launcher/url_launcher.dart';
const kDescriptionWidth = 300.0;
class DescriptionPopover extends StatelessWidget {
- final ExampleModel example;
+ final ExampleBase example;
const DescriptionPopover({Key? key, required this.example}) : super(key: key);
diff --git a/playground/frontend/lib/modules/examples/components/description_popover/description_popover_button.dart b/playground/frontend/lib/modules/examples/components/description_popover/description_popover_button.dart
index 5e935eb0328d..8df888ed76fa 100644
--- a/playground/frontend/lib/modules/examples/components/description_popover/description_popover_button.dart
+++ b/playground/frontend/lib/modules/examples/components/description_popover/description_popover_button.dart
@@ -19,14 +19,13 @@
import 'package:aligned_dialog/aligned_dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-import 'package:playground/config/theme.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/examples/components/description_popover/description_popover.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground_components/playground_components.dart';
class DescriptionPopoverButton extends StatelessWidget {
final BuildContext? parentContext;
- final ExampleModel example;
+ final ExampleBase example;
final Alignment followerAnchor;
final Alignment targetAnchor;
final void Function()? onOpen;
@@ -52,7 +51,7 @@ class DescriptionPopoverButton extends StatelessWidget {
splashRadius: kIconButtonSplashRadius,
icon: Icon(
Icons.info_outline_rounded,
- color: ThemeColors.of(context).grey1Color,
+ color: Theme.of(context).extension()?.iconColor,
),
tooltip: appLocale.exampleDescription,
onPressed: () {
@@ -69,7 +68,7 @@ class DescriptionPopoverButton extends StatelessWidget {
void _showDescriptionPopover(
BuildContext context,
- ExampleModel example,
+ ExampleBase example,
Alignment followerAnchor,
Alignment targetAnchor,
) async {
diff --git a/playground/frontend/lib/modules/examples/components/example_list/category_expansion_panel.dart b/playground/frontend/lib/modules/examples/components/example_list/category_expansion_panel.dart
index c6dcf47271e6..049db9e5968e 100644
--- a/playground/frontend/lib/modules/examples/components/example_list/category_expansion_panel.dart
+++ b/playground/frontend/lib/modules/examples/components/example_list/category_expansion_panel.dart
@@ -22,12 +22,12 @@ import 'package:expansion_widget/expansion_widget.dart';
import 'package:flutter/material.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/examples/components/example_list/expansion_panel_item.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground_components/playground_components.dart';
class CategoryExpansionPanel extends StatelessWidget {
final String categoryName;
final List examples;
- final ExampleModel selectedExample;
+ final ExampleBase selectedExample;
final AnimationController animationController;
final OverlayEntry? dropdown;
diff --git a/playground/frontend/lib/modules/examples/components/example_list/example_item_actions.dart b/playground/frontend/lib/modules/examples/components/example_list/example_item_actions.dart
index 9cae77f6073b..584b4c157316 100644
--- a/playground/frontend/lib/modules/examples/components/example_list/example_item_actions.dart
+++ b/playground/frontend/lib/modules/examples/components/example_list/example_item_actions.dart
@@ -18,14 +18,13 @@
import 'package:flutter/material.dart';
import 'package:playground/modules/examples/components/description_popover/description_popover_button.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground/modules/examples/components/multifile_popover/multifile_popover_button.dart';
import 'package:playground/modules/examples/models/popover_state.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:provider/provider.dart';
-import '../multifile_popover/multifile_popover_button.dart';
-
class ExampleItemActions extends StatelessWidget {
- final ExampleModel example;
+ final ExampleBase example;
final BuildContext parentContext;
const ExampleItemActions(
diff --git a/playground/frontend/lib/modules/examples/components/example_list/example_list.dart b/playground/frontend/lib/modules/examples/components/example_list/example_list.dart
index 6b175e2692a1..1c9227d2f59e 100644
--- a/playground/frontend/lib/modules/examples/components/example_list/example_list.dart
+++ b/playground/frontend/lib/modules/examples/components/example_list/example_list.dart
@@ -18,15 +18,15 @@
import 'package:flutter/material.dart';
import 'package:playground/modules/examples/components/examples_components.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
import 'package:playground/pages/playground/states/example_selector_state.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:provider/provider.dart';
class ExampleList extends StatelessWidget {
final ScrollController controller;
final AnimationController animationController;
final OverlayEntry? dropdown;
- final ExampleModel selectedExample;
+ final ExampleBase selectedExample;
const ExampleList({
Key? key,
@@ -50,7 +50,7 @@ class ExampleList extends StatelessWidget {
itemCount: state.categories.length,
itemBuilder: (context, index) => CategoryExpansionPanel(
selectedExample: selectedExample,
- categoryName: state.categories[index].name,
+ categoryName: state.categories[index].title,
examples: state.categories[index].examples,
animationController: animationController,
dropdown: dropdown,
diff --git a/playground/frontend/lib/modules/examples/components/example_list/expansion_panel_item.dart b/playground/frontend/lib/modules/examples/components/example_list/expansion_panel_item.dart
index f212f3c07e4c..b035e35d2d99 100644
--- a/playground/frontend/lib/modules/examples/components/example_list/expansion_panel_item.dart
+++ b/playground/frontend/lib/modules/examples/components/example_list/expansion_panel_item.dart
@@ -20,14 +20,12 @@ import 'package:flutter/material.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/analytics/analytics_service.dart';
import 'package:playground/modules/examples/components/example_list/example_item_actions.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
-import 'package:playground/pages/playground/states/examples_state.dart';
-import 'package:playground/pages/playground/states/playground_state.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:provider/provider.dart';
class ExpansionPanelItem extends StatelessWidget {
- final ExampleModel example;
- final ExampleModel selectedExample;
+ final ExampleBase example;
+ final ExampleBase selectedExample;
final AnimationController animationController;
final OverlayEntry? dropdown;
@@ -41,20 +39,21 @@ class ExpansionPanelItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Consumer(
- builder: (context, playgroundState, child) => MouseRegion(
+ return Consumer(
+ builder: (context, controller, child) => MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () async {
- if (playgroundState.selectedExample != example) {
- _closeDropdown(playgroundState.exampleState);
+ if (controller.selectedExample != example) {
+ _closeDropdown(controller.exampleCache);
AnalyticsService.get(context).trackSelectExample(example);
final exampleWithInfo =
- await playgroundState.exampleState.loadExampleInfo(example);
+ await controller.exampleCache.loadExampleInfo(example);
// TODO: setCurrentSdk = false when we do
// per-SDK output and run status.
// Now using true to reset the output and run status.
- playgroundState.setExample(exampleWithInfo, setCurrentSdk: true);
+ // https://github.com/apache/beam/issues/23248
+ controller.setExample(exampleWithInfo, setCurrentSdk: true);
}
},
child: Container(
@@ -83,9 +82,9 @@ class ExpansionPanelItem extends StatelessWidget {
);
}
- void _closeDropdown(ExampleState exampleState) {
+ void _closeDropdown(ExampleCache exampleCache) {
animationController.reverse();
dropdown?.remove();
- exampleState.changeSelectorVisibility();
+ exampleCache.changeSelectorVisibility();
}
}
diff --git a/playground/frontend/lib/modules/examples/components/filter/category_bubble.dart b/playground/frontend/lib/modules/examples/components/filter/category_bubble.dart
index aabe00735ee6..849f19db877c 100644
--- a/playground/frontend/lib/modules/examples/components/filter/category_bubble.dart
+++ b/playground/frontend/lib/modules/examples/components/filter/category_bubble.dart
@@ -17,10 +17,8 @@
*/
import 'package:flutter/material.dart';
-import 'package:playground/config/theme.dart';
-import 'package:playground/constants/sizes.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
import 'package:playground/pages/playground/states/example_selector_state.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:provider/provider.dart';
class CategoryBubble extends StatelessWidget {
@@ -35,46 +33,21 @@ class CategoryBubble extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return MouseRegion(
- cursor: SystemMouseCursors.click,
- child: Padding(
- padding: const EdgeInsets.only(right: kMdSpacing),
- child: Consumer(
- builder: (context, state, child) {
- final isSelected = type == state.selectedFilterType;
+ return Consumer(
+ builder: (context, state, child) {
+ final isSelected = type == state.selectedFilterType;
- return GestureDetector(
- onTap: () {
- if (!isSelected) {
- state.setSelectedFilterType(type);
- state.sortCategories();
- }
- },
- child: Container(
- height: kContainerHeight,
- padding: const EdgeInsets.symmetric(horizontal: kXlSpacing),
- decoration: BoxDecoration(
- color: isSelected
- ? ThemeColors.of(context).primary
- : ThemeColors.of(context).lightGreyColor,
- borderRadius: BorderRadius.circular(kXlBorderRadius),
- ),
- child: Center(
- child: Text(
- name,
- style: TextStyle(
- color: isSelected
- ? ThemeColors.of(context).primaryBackgroundTextColor
- : ThemeColors.of(context)
- .lightGreyBackgroundTextColor,
- ),
- ),
- ),
- ),
- );
+ return BubbleWidget(
+ isSelected: isSelected,
+ title: name,
+ onTap: () {
+ if (!isSelected) {
+ state.setSelectedFilterType(type);
+ state.sortCategories();
+ }
},
- ),
- ),
+ );
+ },
);
}
}
diff --git a/playground/frontend/lib/modules/examples/components/filter/type_filter.dart b/playground/frontend/lib/modules/examples/components/filter/type_filter.dart
index c56f6fcde415..a221999f3ce6 100644
--- a/playground/frontend/lib/modules/examples/components/filter/type_filter.dart
+++ b/playground/frontend/lib/modules/examples/components/filter/type_filter.dart
@@ -20,7 +20,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/examples/components/examples_components.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground_components/playground_components.dart';
class TypeFilter extends StatelessWidget {
const TypeFilter({Key? key}) : super(key: key);
diff --git a/playground/frontend/lib/modules/examples/components/multifile_popover/multifile_popover.dart b/playground/frontend/lib/modules/examples/components/multifile_popover/multifile_popover.dart
index 6d90bc7bfd56..c4fb93fa4706 100644
--- a/playground/frontend/lib/modules/examples/components/multifile_popover/multifile_popover.dart
+++ b/playground/frontend/lib/modules/examples/components/multifile_popover/multifile_popover.dart
@@ -22,13 +22,13 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:playground/constants/assets.dart';
import 'package:playground/constants/font_weight.dart';
import 'package:playground/constants/sizes.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:url_launcher/url_launcher.dart';
const kMultifileWidth = 300.0;
class MultifilePopover extends StatelessWidget {
- final ExampleModel example;
+ final ExampleBase example;
const MultifilePopover({Key? key, required this.example}) : super(key: key);
diff --git a/playground/frontend/lib/modules/examples/components/multifile_popover/multifile_popover_button.dart b/playground/frontend/lib/modules/examples/components/multifile_popover/multifile_popover_button.dart
index 069830c65c76..d530aa645ebe 100644
--- a/playground/frontend/lib/modules/examples/components/multifile_popover/multifile_popover_button.dart
+++ b/playground/frontend/lib/modules/examples/components/multifile_popover/multifile_popover_button.dart
@@ -23,11 +23,11 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:playground/constants/assets.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/examples/components/multifile_popover/multifile_popover.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground_components/playground_components.dart';
class MultifilePopoverButton extends StatelessWidget {
final BuildContext? parentContext;
- final ExampleModel example;
+ final ExampleBase example;
final Alignment followerAnchor;
final Alignment targetAnchor;
final void Function()? onOpen;
@@ -67,7 +67,7 @@ class MultifilePopoverButton extends StatelessWidget {
void _showMultifilePopover(
BuildContext context,
- ExampleModel example,
+ ExampleBase example,
Alignment followerAnchor,
Alignment targetAnchor,
) async {
diff --git a/playground/frontend/lib/modules/examples/components/search_field/search_field.dart b/playground/frontend/lib/modules/examples/components/search_field/search_field.dart
index 80939ac15554..2095dfac1d23 100644
--- a/playground/frontend/lib/modules/examples/components/search_field/search_field.dart
+++ b/playground/frontend/lib/modules/examples/components/search_field/search_field.dart
@@ -18,9 +18,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-import 'package:playground/config/theme.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/pages/playground/states/example_selector_state.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:provider/provider.dart';
const double kContainerWidth = 376.0;
@@ -34,8 +34,11 @@ class SearchField extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final borderColor =
+ Theme.of(context).extension()!.borderColor;
+
final OutlineInputBorder border = OutlineInputBorder(
- borderSide: BorderSide(color: ThemeColors.of(context).lightGreyColor),
+ borderSide: BorderSide(color: borderColor),
borderRadius: BorderRadius.circular(kMdBorderRadius),
);
@@ -61,7 +64,7 @@ class SearchField extends StatelessWidget {
),
child: Icon(
Icons.search,
- color: ThemeColors.of(context).lightGreyColor,
+ color: borderColor,
size: kIconSizeMd,
),
),
@@ -72,7 +75,7 @@ class SearchField extends StatelessWidget {
hintText: AppLocalizations.of(context)!.search,
contentPadding: const EdgeInsets.only(left: kLgSpacing),
),
- cursorColor: ThemeColors.of(context).lightGreyColor,
+ cursorColor: borderColor,
cursorWidth: kCursorSize,
textAlignVertical: TextAlignVertical.center,
onFieldSubmitted: (String filterText) =>
diff --git a/playground/frontend/lib/modules/examples/example_selector.dart b/playground/frontend/lib/modules/examples/example_selector.dart
index f65c45bfacfd..c08fdb3cea2d 100644
--- a/playground/frontend/lib/modules/examples/example_selector.dart
+++ b/playground/frontend/lib/modules/examples/example_selector.dart
@@ -18,18 +18,14 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-import 'package:playground/components/horizontal_divider/horizontal_divider.dart';
-import 'package:playground/components/loading_indicator/loading_indicator.dart';
-import 'package:playground/config/theme.dart';
import 'package:playground/constants/links.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/examples/components/examples_components.dart';
import 'package:playground/modules/examples/components/outside_click_handler.dart';
import 'package:playground/modules/examples/models/popover_state.dart';
import 'package:playground/pages/playground/states/example_selector_state.dart';
-import 'package:playground/pages/playground/states/examples_state.dart';
-import 'package:playground/pages/playground/states/playground_state.dart';
import 'package:playground/utils/dropdown_utils.dart';
+import 'package:playground_components/playground_components.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -90,10 +86,10 @@ class _ExampleSelectorState extends State
return Container(
height: kContainerHeight,
decoration: BoxDecoration(
- color: ThemeColors.of(context).dropdownButton,
+ color: Theme.of(context).dividerColor,
borderRadius: BorderRadius.circular(kSmBorderRadius),
),
- child: Consumer(
+ child: Consumer(
builder: (context, state, child) => TextButton(
key: selectorKey,
onPressed: () {
@@ -111,7 +107,7 @@ class _ExampleSelectorState extends State
alignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
- Consumer(
+ Consumer(
builder: (context, state, child) => Text(state.examplesTitle),
),
const Icon(Icons.keyboard_arrow_down),
@@ -130,12 +126,12 @@ class _ExampleSelectorState extends State
return ChangeNotifierProvider(
create: (context) => PopoverState(false),
builder: (context, state) {
- return Consumer(
- builder: (context, playgroundState, child) => Stack(
+ return Consumer(
+ builder: (context, playgroundController, child) => Stack(
children: [
OutsideClickHandler(
onTap: () {
- _closeDropdown(playgroundState.exampleState);
+ _closeDropdown(playgroundController.exampleCache);
// handle description dialogs
Navigator.of(context, rootNavigator: true)
.popUntil((route) {
@@ -145,9 +141,9 @@ class _ExampleSelectorState extends State
),
ChangeNotifierProvider(
create: (context) => ExampleSelectorState(
- playgroundState,
- playgroundState.exampleState
- .getCategories(playgroundState.sdk),
+ playgroundController,
+ playgroundController.exampleCache
+ .getCategories(playgroundController.sdk),
),
builder: (context, _) => Positioned(
left: dropdownOffset.dx,
@@ -166,7 +162,7 @@ class _ExampleSelectorState extends State
),
child: _buildDropdownContent(
context,
- playgroundState,
+ playgroundController,
),
),
),
@@ -184,13 +180,11 @@ class _ExampleSelectorState extends State
Widget _buildDropdownContent(
BuildContext context,
- PlaygroundState playgroundState,
+ PlaygroundController playgroundController,
) {
- if (playgroundState.exampleState.sdkCategories == null ||
- playgroundState.selectedExample == null) {
- return const LoadingIndicator(
- size: kMdLoadingIndicatorSize,
- );
+ if (playgroundController.exampleCache.categoryListsBySdk.isEmpty ||
+ playgroundController.selectedExample == null) {
+ return const LoadingIndicator();
}
return Column(
@@ -199,11 +193,11 @@ class _ExampleSelectorState extends State
const TypeFilter(),
ExampleList(
controller: scrollController,
- selectedExample: playgroundState.selectedExample!,
+ selectedExample: playgroundController.selectedExample!,
animationController: animationController,
dropdown: examplesDropdown,
),
- const HorizontalDivider(indent: kLgSpacing),
+ const BeamDivider(),
SizedBox(
width: double.infinity,
child: TextButton(
@@ -213,7 +207,7 @@ class _ExampleSelectorState extends State
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context)!.addExample,
- style: TextStyle(color: ThemeColors.of(context).primary),
+ style: TextStyle(color: Theme.of(context).primaryColor),
),
),
),
@@ -224,9 +218,9 @@ class _ExampleSelectorState extends State
);
}
- void _closeDropdown(ExampleState exampleState) {
+ void _closeDropdown(ExampleCache exampleCache) {
animationController.reverse();
examplesDropdown?.remove();
- exampleState.changeSelectorVisibility();
+ exampleCache.changeSelectorVisibility();
}
}
diff --git a/playground/frontend/lib/modules/examples/models/example_loading_descriptors/catalog_default_example_loading_descriptor.dart b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/catalog_default_example_loading_descriptor.dart
deleted file mode 100644
index 5841e0e294c6..000000000000
--- a/playground/frontend/lib/modules/examples/models/example_loading_descriptors/catalog_default_example_loading_descriptor.dart
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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:playground/modules/sdk/models/sdk.dart';
-import 'package:playground/modules/examples/models/example_loading_descriptors/example_loading_descriptor.dart';
-import 'package:playground/modules/examples/models/example_origin.dart';
-
-class CatalogDefaultExampleLoadingDescriptor extends ExampleLoadingDescriptor {
- final SDK sdk;
-
- const CatalogDefaultExampleLoadingDescriptor({
- required this.sdk,
- });
-
- @override
- ExampleOrigin get origin => ExampleOrigin.catalogDefault;
-
- @override
- int get hashCode => sdk.hashCode;
-
- @override
- bool operator ==(Object other) {
- return other is CatalogDefaultExampleLoadingDescriptor && sdk == other.sdk;
- }
-
- // Only ContentExampleLoadingDescriptor is serialized now.
- @override
- Map toJson() => throw UnimplementedError();
-}
diff --git a/playground/frontend/lib/modules/examples/models/example_loading_descriptors/examples_loading_descriptor_factory.dart b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/examples_loading_descriptor_factory.dart
index ca9199f12855..7b3854d6f31f 100644
--- a/playground/frontend/lib/modules/examples/models/example_loading_descriptors/examples_loading_descriptor_factory.dart
+++ b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/examples_loading_descriptor_factory.dart
@@ -19,18 +19,11 @@
import 'dart:convert';
import 'package:playground/constants/params.dart';
-import 'package:playground/modules/examples/models/example_loading_descriptors/catalog_default_example_loading_descriptor.dart';
-import 'package:playground/modules/examples/models/example_loading_descriptors/content_example_loading_descriptor.dart';
-import 'package:playground/modules/examples/models/example_loading_descriptors/empty_example_loading_descriptor.dart';
-import 'package:playground/modules/examples/models/example_loading_descriptors/example_loading_descriptor.dart';
-import 'package:playground/modules/examples/models/example_loading_descriptors/examples_loading_descriptor.dart';
-import 'package:playground/modules/examples/models/example_loading_descriptors/standard_example_loading_descriptor.dart';
-import 'package:playground/modules/examples/models/example_loading_descriptors/user_shared_example_loading_descriptor.dart';
import 'package:playground/modules/examples/models/example_token_type.dart';
-import 'package:playground/modules/sdk/models/sdk.dart';
+import 'package:playground_components/playground_components.dart';
class ExamplesLoadingDescriptorFactory {
- static const _defaultSdk = SDK.java;
+ static const _defaultSdk = Sdk.java;
static ExamplesLoadingDescriptor fromUriParts({
required String path,
@@ -61,7 +54,7 @@ class ExamplesLoadingDescriptorFactory {
return null;
}
- final sdk = SDK.tryParse(params[kSdkParam]);
+ final sdk = Sdk.tryParse(params[kSdkParam]);
return ExamplesLoadingDescriptor(
descriptors: _parseMultipleInstantExamples(list, sdk),
@@ -75,7 +68,7 @@ class ExamplesLoadingDescriptorFactory {
static List _parseMultipleInstantExamples(
List list,
- SDK? sdk,
+ Sdk? sdk,
) {
final result = [];
@@ -132,7 +125,7 @@ class ExamplesLoadingDescriptorFactory {
return null;
}
- final sdk = SDK.tryParse(params[kSdkParam]) ?? _defaultSdk;
+ final sdk = Sdk.tryParse(params[kSdkParam]) ?? _defaultSdk;
return ExamplesLoadingDescriptor(
descriptors: [
@@ -161,14 +154,14 @@ class ExamplesLoadingDescriptorFactory {
return ExamplesLoadingDescriptor(
descriptors: [
EmptyExampleLoadingDescriptor(
- sdk: SDK.tryParse(params[kSdkParam]) ?? _defaultSdk,
+ sdk: Sdk.tryParse(params[kSdkParam]) ?? _defaultSdk,
),
],
lazyLoadDescriptors: _emptyLazyLoadDescriptors,
);
}
- static Map> _getLazyLoadDescriptors() {
+ static Map> _getLazyLoadDescriptors() {
if (isEmbedded()) {
return _emptyLazyLoadDescriptors;
}
@@ -176,18 +169,18 @@ class ExamplesLoadingDescriptorFactory {
return _defaultLazyLoadDescriptors;
}
- static Map>
+ static Map>
get _emptyLazyLoadDescriptors {
return {
- for (final sdk in SDK.values)
+ for (final sdk in Sdk.known)
sdk: [EmptyExampleLoadingDescriptor(sdk: sdk)]
};
}
- static Map>
+ static Map>
get _defaultLazyLoadDescriptors {
return {
- for (final sdk in SDK.values)
+ for (final sdk in Sdk.known)
sdk: [CatalogDefaultExampleLoadingDescriptor(sdk: sdk)]
};
}
diff --git a/playground/frontend/lib/modules/examples/models/example_loading_descriptors/standard_example_loading_descriptor.dart b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/standard_example_loading_descriptor.dart
deleted file mode 100644
index a5adbff51ac6..000000000000
--- a/playground/frontend/lib/modules/examples/models/example_loading_descriptors/standard_example_loading_descriptor.dart
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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:playground/modules/examples/models/example_loading_descriptors/example_loading_descriptor.dart';
-import 'package:playground/modules/examples/models/example_origin.dart';
-
-class StandardExampleLoadingDescriptor extends ExampleLoadingDescriptor {
- final String path;
-
- const StandardExampleLoadingDescriptor({
- required this.path,
- });
-
- @override
- ExampleOrigin get origin => ExampleOrigin.standard;
-
- @override
- String toString() => '$origin-$path';
-
- @override
- int get hashCode => path.hashCode;
-
- @override
- bool operator ==(Object other) {
- return other is StandardExampleLoadingDescriptor && path == other.path;
- }
-
- // Only ContentExampleLoadingDescriptor is serialized now.
- @override
- Map toJson() => throw UnimplementedError();
-}
diff --git a/playground/frontend/lib/modules/examples/models/example_loading_descriptors/user_shared_example_loading_descriptor.dart b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/user_shared_example_loading_descriptor.dart
deleted file mode 100644
index 26e58a8453fb..000000000000
--- a/playground/frontend/lib/modules/examples/models/example_loading_descriptors/user_shared_example_loading_descriptor.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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:playground/modules/examples/models/example_loading_descriptors/example_loading_descriptor.dart';
-import 'package:playground/modules/examples/models/example_origin.dart';
-
-class UserSharedExampleLoadingDescriptor extends ExampleLoadingDescriptor {
- final String snippetId;
-
- const UserSharedExampleLoadingDescriptor({
- required this.snippetId,
- });
-
- @override
- ExampleOrigin get origin => ExampleOrigin.userShared;
-
- @override
- String toString() => '$origin-$snippetId';
-
- @override
- int get hashCode => snippetId.hashCode;
-
- @override
- bool operator ==(Object other) {
- return other is UserSharedExampleLoadingDescriptor &&
- snippetId == other.snippetId;
- }
-
- // Only ContentExampleLoadingDescriptor is serialized now.
- @override
- Map toJson() => throw UnimplementedError();
-}
diff --git a/playground/frontend/lib/modules/examples/models/example_token_type.dart b/playground/frontend/lib/modules/examples/models/example_token_type.dart
index 789b1c3a179a..48c7c5806358 100644
--- a/playground/frontend/lib/modules/examples/models/example_token_type.dart
+++ b/playground/frontend/lib/modules/examples/models/example_token_type.dart
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-import 'package:playground/modules/sdk/models/sdk.dart';
+import 'package:playground_components/playground_components.dart';
enum ExampleTokenType {
standard,
@@ -24,7 +24,7 @@ enum ExampleTokenType {
;
static ExampleTokenType fromToken(String token) {
- final sdk = SDK.tryParseExamplePath(token);
+ final sdk = Sdk.tryParseExamplePath(token);
if (sdk != null) {
return standard;
}
diff --git a/playground/frontend/lib/modules/examples/repositories/example_client/example_client.dart b/playground/frontend/lib/modules/examples/repositories/example_client/example_client.dart
deleted file mode 100644
index 039a567c5efa..000000000000
--- a/playground/frontend/lib/modules/examples/repositories/example_client/example_client.dart
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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:playground/modules/editor/repository/code_repository/code_client/output_response.dart';
-import 'package:playground/modules/examples/repositories/models/get_snippet_request.dart';
-import 'package:playground/modules/examples/repositories/models/get_snippet_response.dart';
-import 'package:playground/modules/examples/repositories/models/get_example_code_response.dart';
-import 'package:playground/modules/examples/repositories/models/get_example_request.dart';
-import 'package:playground/modules/examples/repositories/models/get_example_response.dart';
-import 'package:playground/modules/examples/repositories/models/get_list_of_examples_request.dart';
-import 'package:playground/modules/examples/repositories/models/get_list_of_examples_response.dart';
-import 'package:playground/modules/examples/repositories/models/save_snippet_request.dart';
-import 'package:playground/modules/examples/repositories/models/save_snippet_response.dart';
-
-abstract class ExampleClient {
- Future getListOfExamples(
- GetListOfExamplesRequestWrapper request,
- );
-
- Future getExampleSource(
- GetExampleRequestWrapper request,
- );
-
- Future getDefaultExample(
- GetExampleRequestWrapper request,
- );
-
- Future getExample(
- GetExampleRequestWrapper request,
- );
-
- Future getExampleOutput(
- GetExampleRequestWrapper request,
- );
-
- Future getExampleLogs(
- GetExampleRequestWrapper request,
- );
-
- Future getExampleGraph(
- GetExampleRequestWrapper request,
- );
-
- Future getSnippet(
- GetSnippetRequestWrapper request,
- );
-
- Future saveSnippet(
- SaveSnippetRequestWrapper request,
- );
-}
diff --git a/playground/frontend/lib/modules/examples/repositories/example_client/grpc_example_client.dart b/playground/frontend/lib/modules/examples/repositories/example_client/grpc_example_client.dart
deleted file mode 100644
index f4a11be58aae..000000000000
--- a/playground/frontend/lib/modules/examples/repositories/example_client/grpc_example_client.dart
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * 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:grpc/grpc_web.dart';
-import 'package:playground/api/iis_workaround_channel.dart';
-import 'package:playground/api/v1/api.pbgrpc.dart' as grpc;
-import 'package:playground/config.g.dart';
-import 'package:playground/modules/editor/repository/code_repository/code_client/output_response.dart';
-import 'package:playground/modules/examples/models/category_model.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
-import 'package:playground/modules/examples/repositories/example_client/example_client.dart';
-import 'package:playground/modules/examples/repositories/models/get_example_code_response.dart';
-import 'package:playground/modules/examples/repositories/models/get_example_request.dart';
-import 'package:playground/modules/examples/repositories/models/get_example_response.dart';
-import 'package:playground/modules/examples/repositories/models/get_list_of_examples_request.dart';
-import 'package:playground/modules/examples/repositories/models/get_list_of_examples_response.dart';
-import 'package:playground/modules/examples/repositories/models/get_snippet_request.dart';
-import 'package:playground/modules/examples/repositories/models/get_snippet_response.dart';
-import 'package:playground/modules/examples/repositories/models/save_snippet_request.dart';
-import 'package:playground/modules/examples/repositories/models/save_snippet_response.dart';
-import 'package:playground/modules/examples/repositories/models/shared_file_model.dart';
-import 'package:playground/modules/sdk/models/sdk.dart';
-import 'package:playground/utils/replace_incorrect_symbols.dart';
-
-class GrpcExampleClient implements ExampleClient {
- late final grpc.PlaygroundServiceClient _defaultClient;
-
- GrpcExampleClient() {
- final channel = IisWorkaroundChannel.xhr(
- Uri.parse(kApiClientURL),
- );
- _defaultClient = grpc.PlaygroundServiceClient(channel);
- }
-
- @override
- Future getListOfExamples(
- GetListOfExamplesRequestWrapper request,
- ) {
- return _runSafely(
- () => _defaultClient
- .getPrecompiledObjects(
- _getListOfExamplesRequestToGrpcRequest(request))
- .then((response) => GetListOfExampleResponse(
- _toClientCategories(response.sdkCategories))),
- );
- }
-
- @override
- Future getDefaultExample(
- GetExampleRequestWrapper request,
- ) {
- return _runSafely(
- () => _defaultClient
- .getDefaultPrecompiledObject(
- _getDefaultExampleRequestToGrpcRequest(request))
- .then(
- (response) => GetExampleResponse(
- _toExampleModel(
- request.sdk,
- response.precompiledObject,
- ),
- ),
- ),
- );
- }
-
- @override
- Future getExample(
- GetExampleRequestWrapper request,
- ) {
- return _runSafely(
- () => _defaultClient
- .getPrecompiledObject(
- grpc.GetPrecompiledObjectRequest()..cloudPath = request.path)
- .then(
- (response) => GetExampleResponse(
- _toExampleModel(
- request.sdk,
- response.precompiledObject,
- ),
- ),
- ),
- );
- }
-
- @override
- Future getExampleSource(
- GetExampleRequestWrapper request) {
- return _runSafely(
- () => _defaultClient
- .getPrecompiledObjectCode(
- _getExampleCodeRequestToGrpcRequest(request))
- .then((response) =>
- GetExampleCodeResponse(replaceIncorrectSymbols(response.code))),
- );
- }
-
- @override
- Future getExampleOutput(GetExampleRequestWrapper request) {
- return _runSafely(
- () => _defaultClient
- .getPrecompiledObjectOutput(
- _getExampleOutputRequestToGrpcRequest(request))
- .then((response) =>
- OutputResponse(replaceIncorrectSymbols(response.output)))
- .catchError((err) {
- print(err);
- return OutputResponse('');
- }),
- );
- }
-
- @override
- Future getExampleLogs(GetExampleRequestWrapper request) {
- return _runSafely(
- () => _defaultClient
- .getPrecompiledObjectLogs(_getExampleLogRequestToGrpcRequest(request))
- .then((response) =>
- OutputResponse(replaceIncorrectSymbols(response.output)))
- .catchError((err) {
- print(err);
- return OutputResponse('');
- }),
- );
- }
-
- @override
- Future getExampleGraph(GetExampleRequestWrapper request) {
- return _runSafely(
- () => _defaultClient
- .getPrecompiledObjectGraph(
- _getExampleGraphRequestToGrpcRequest(request))
- .then((response) => OutputResponse(response.graph))
- .catchError((err) {
- print(err);
- return OutputResponse('');
- }),
- );
- }
-
- @override
- Future getSnippet(
- GetSnippetRequestWrapper request,
- ) {
- return _runSafely(
- () => _defaultClient
- .getSnippet(_getSnippetRequestToGrpcRequest(request))
- .then(
- (response) => GetSnippetResponse(
- files: _convertToSharedFileList(response.files),
- sdk: _getAppSdk(response.sdk),
- pipelineOptions: response.pipelineOptions,
- ),
- ),
- );
- }
-
- @override
- Future saveSnippet(
- SaveSnippetRequestWrapper request,
- ) {
- return _runSafely(
- () => _defaultClient
- .saveSnippet(_saveSnippetRequestToGrpcRequest(request))
- .then(
- (response) => SaveSnippetResponse(
- id: response.id,
- ),
- ),
- );
- }
-
- Future _runSafely(Future Function() invoke) {
- try {
- return invoke();
- } on GrpcError catch (error) {
- throw Exception(error.message);
- }
- }
-
- grpc.GetPrecompiledObjectsRequest _getListOfExamplesRequestToGrpcRequest(
- GetListOfExamplesRequestWrapper request,
- ) {
- return grpc.GetPrecompiledObjectsRequest()
- ..category = request.category ?? ''
- ..sdk = request.sdk == null
- ? grpc.Sdk.SDK_UNSPECIFIED
- : _getGrpcSdk(request.sdk!);
- }
-
- grpc.GetDefaultPrecompiledObjectRequest
- _getDefaultExampleRequestToGrpcRequest(
- GetExampleRequestWrapper request,
- ) {
- return grpc.GetDefaultPrecompiledObjectRequest()
- ..sdk = _getGrpcSdk(request.sdk);
- }
-
- grpc.GetPrecompiledObjectCodeRequest _getExampleCodeRequestToGrpcRequest(
- GetExampleRequestWrapper request,
- ) {
- return grpc.GetPrecompiledObjectCodeRequest()..cloudPath = request.path;
- }
-
- grpc.GetPrecompiledObjectOutputRequest _getExampleOutputRequestToGrpcRequest(
- GetExampleRequestWrapper request,
- ) {
- return grpc.GetPrecompiledObjectOutputRequest()..cloudPath = request.path;
- }
-
- grpc.GetPrecompiledObjectLogsRequest _getExampleLogRequestToGrpcRequest(
- GetExampleRequestWrapper request,
- ) {
- return grpc.GetPrecompiledObjectLogsRequest()..cloudPath = request.path;
- }
-
- grpc.GetPrecompiledObjectGraphRequest _getExampleGraphRequestToGrpcRequest(
- GetExampleRequestWrapper request,
- ) {
- return grpc.GetPrecompiledObjectGraphRequest()..cloudPath = request.path;
- }
-
- grpc.GetSnippetRequest _getSnippetRequestToGrpcRequest(
- GetSnippetRequestWrapper request,
- ) {
- return grpc.GetSnippetRequest()..id = request.id;
- }
-
- grpc.SaveSnippetRequest _saveSnippetRequestToGrpcRequest(
- SaveSnippetRequestWrapper request,
- ) {
- return grpc.SaveSnippetRequest()
- ..sdk = _getGrpcSdk(request.sdk)
- ..pipelineOptions = request.pipelineOptions
- ..files.addAll(_convertToSnippetFileList(request.files));
- }
-
- grpc.Sdk _getGrpcSdk(SDK sdk) {
- switch (sdk) {
- case SDK.java:
- return grpc.Sdk.SDK_JAVA;
- case SDK.go:
- return grpc.Sdk.SDK_GO;
- case SDK.python:
- return grpc.Sdk.SDK_PYTHON;
- case SDK.scio:
- return grpc.Sdk.SDK_SCIO;
- }
- }
-
- SDK _getAppSdk(grpc.Sdk sdk) {
- switch (sdk) {
- case grpc.Sdk.SDK_JAVA:
- return SDK.java;
- case grpc.Sdk.SDK_GO:
- return SDK.go;
- case grpc.Sdk.SDK_PYTHON:
- return SDK.python;
- case grpc.Sdk.SDK_SCIO:
- return SDK.scio;
- default:
- return SDK.java;
- }
- }
-
- ExampleType _exampleTypeFromString(grpc.PrecompiledObjectType type) {
- switch (type) {
- case grpc.PrecompiledObjectType.PRECOMPILED_OBJECT_TYPE_EXAMPLE:
- return ExampleType.example;
- case grpc.PrecompiledObjectType.PRECOMPILED_OBJECT_TYPE_KATA:
- return ExampleType.kata;
- case grpc.PrecompiledObjectType.PRECOMPILED_OBJECT_TYPE_UNIT_TEST:
- return ExampleType.test;
- case grpc.PrecompiledObjectType.PRECOMPILED_OBJECT_TYPE_UNSPECIFIED:
- return ExampleType.all;
- default:
- return ExampleType.example;
- }
- }
-
- Map> _toClientCategories(
- List response,
- ) {
- Map> sdkCategoriesMap = {};
- List>> entries = [];
- for (var sdkMap in response) {
- SDK sdk = _getAppSdk(sdkMap.sdk);
- List categoriesForSdk = [];
- for (var category in sdkMap.categories) {
- List examples = category.precompiledObjects
- .map((example) => _toExampleModel(sdk, example))
- .toList()
- ..sort();
- categoriesForSdk.add(CategoryModel(
- name: category.categoryName,
- examples: examples,
- ));
- }
- entries.add(MapEntry(sdk, categoriesForSdk..sort()));
- }
- sdkCategoriesMap.addEntries(entries);
- return sdkCategoriesMap;
- }
-
- ExampleModel _toExampleModel(SDK sdk, grpc.PrecompiledObject example) {
- return ExampleModel(
- sdk: sdk,
- name: example.name,
- description: example.description,
- type: _exampleTypeFromString(example.type),
- path: example.cloudPath,
- contextLine: example.contextLine,
- pipelineOptions: example.pipelineOptions,
- isMultiFile: example.multifile,
- link: example.link,
- );
- }
-
- List _convertToSharedFileList(
- List snippetFileList,
- ) {
- final sharedFilesList = [];
-
- for (grpc.SnippetFile item in snippetFileList) {
- sharedFilesList.add(SharedFile(
- code: item.content,
- isMain: item.isMain,
- name: item.name,
- ));
- }
-
- return sharedFilesList;
- }
-
- List _convertToSnippetFileList(
- List sharedFilesList,
- ) {
- final snippetFileList = [];
-
- for (SharedFile item in sharedFilesList) {
- snippetFileList.add(
- grpc.SnippetFile()
- ..name = item.name
- ..isMain = true
- ..content = item.code,
- );
- }
-
- return snippetFileList;
- }
-}
diff --git a/playground/frontend/lib/modules/examples/repositories/example_repository.dart b/playground/frontend/lib/modules/examples/repositories/example_repository.dart
deleted file mode 100644
index 65c09f885fba..000000000000
--- a/playground/frontend/lib/modules/examples/repositories/example_repository.dart
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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:playground/modules/examples/models/category_model.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
-import 'package:playground/modules/examples/repositories/example_client/example_client.dart';
-import 'package:playground/modules/examples/repositories/models/get_snippet_request.dart';
-import 'package:playground/modules/examples/repositories/models/get_snippet_response.dart';
-import 'package:playground/modules/examples/repositories/models/get_example_request.dart';
-import 'package:playground/modules/examples/repositories/models/get_list_of_examples_request.dart';
-import 'package:playground/modules/examples/repositories/models/save_snippet_request.dart';
-import 'package:playground/modules/sdk/models/sdk.dart';
-
-class ExampleRepository {
- late final ExampleClient _client;
-
- ExampleRepository(ExampleClient client) {
- _client = client;
- }
-
- Future