You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beam.apache.org by pa...@apache.org on 2022/08/10 23:10:21 UTC
[beam] branch master updated: [Playground] Share any code feature frontend (#22477)
This is an automated email from the ASF dual-hosted git repository.
pabloem pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git
The following commit(s) were added to refs/heads/master by this push:
new 38cc8bc7cfc [Playground] Share any code feature frontend (#22477)
38cc8bc7cfc is described below
commit 38cc8bc7cfcb393ae959eb774cb7d8da6ea6a2b8
Author: alexeyinkin <al...@akvelon.com>
AuthorDate: Thu Aug 11 03:10:14 2022 +0400
[Playground] Share any code feature frontend (#22477)
* [Playground] Share any code feature (#21978)
* Create separate loaders for different sources of loadable code (#21978)
* Fix dark theme (#21978)
Co-authored-by: Aleksandr Zhuravlev <al...@akvelon.com>
---
playground/frontend/analysis_options.yaml | 1 -
.../dropdown_button/dropdown_button.dart | 53 +++---
.../horizontal_divider.dart} | 27 +--
.../lib/components/split_view/split_view.dart | 2 +-
.../toggle_theme_button/toggle_theme_button.dart | 10 +-
.../toggle_theme_icon_button.dart | 4 +-
playground/frontend/lib/config/theme.dart | 110 +++++++++++-
playground/frontend/lib/constants/params.dart | 8 +-
playground/frontend/lib/constants/sizes.dart | 4 +
playground/frontend/lib/l10n/app_en.arb | 22 ++-
.../modules/editor/components/editor_themes.dart | 5 +-
.../components/share_dropdown/link_text_field.dart | 103 +++++++++++
.../components/share_dropdown/share_button.dart | 58 ++++++
.../share_dropdown/share_dropdown_body.dart} | 54 +++---
.../components/share_dropdown/share_tab_body.dart} | 32 ++--
.../share_tabs/example_share_tabs.dart | 67 +++++++
.../share_dropdown/share_tabs/share_tabs.dart} | 50 +++---
.../share_tabs/snippet_save_and_share_tabs.dart | 56 ++++++
.../share_dropdown/share_tabs_headers.dart} | 35 ++--
.../example_list/expansion_panel_item.dart | 14 +-
.../lib/modules/examples/example_selector.dart | 65 ++++---
...atalog_default_example_loading_descriptor.dart} | 25 ++-
.../empty_example_loading_descriptor.dart} | 25 ++-
.../example_loading_descriptor.dart} | 15 +-
.../examples_loading_descriptor.dart} | 26 ++-
.../examples_loading_descriptor_factory.dart | 79 +++++++++
.../standard_example_loading_descriptor.dart} | 27 ++-
.../user_shared_example_loading_descriptor.dart} | 28 ++-
.../lib/modules/examples/models/example_model.dart | 4 +
...elector_size_model.dart => example_origin.dart} | 27 ++-
...tor_size_model.dart => example_token_type.dart} | 21 ++-
.../example_client/example_client.dart | 28 ++-
.../example_client/grpc_example_client.dart | 110 +++++++++++-
.../examples/repositories/example_repository.dart | 21 ++-
.../models/get_snippet_request.dart} | 10 +-
.../models/get_snippet_response.dart} | 17 +-
.../models/save_snippet_request.dart} | 17 +-
.../models/save_snippet_response.dart} | 10 +-
.../models/shared_file_model.dart} | 14 +-
.../lib/modules/output/components/output.dart | 20 ++-
.../output_header/output_placements.dart | 41 +++--
.../{output_header.dart => tab_header.dart} | 25 +--
.../lib/modules/sdk/components/sdk_selector.dart | 7 +-
.../frontend/lib/modules/sdk/models/sdk.dart | 27 +++
.../components/editor_textarea_wrapper.dart | 9 +-
.../feedback/feedback_dropdown_content.dart | 10 +-
.../components/playground_page_body.dart | 4 +-
.../components/playground_page_providers.dart | 128 +------------
.../lib/pages/playground/playground_page.dart | 13 +-
.../catalog_default_example_loader.dart | 48 +++++
.../example_loaders/empty_example_loader.dart} | 50 ++----
.../states/example_loaders/example_loader.dart} | 12 +-
.../states/example_loaders/examples_loader.dart | 87 +++++++++
.../example_loaders/standard_example_loader.dart | 74 ++++++++
.../user_shared_example_loader.dart} | 21 ++-
.../playground/states/example_selector_state.dart | 17 +-
.../pages/playground/states/examples_state.dart | 92 ++++++++--
.../pages/playground/states/playground_state.dart | 33 +++-
playground/frontend/lib/playground_app.dart | 65 ++++---
playground/frontend/lib/utils/dropdown_utils.dart | 48 +++++
.../frontend/lib/utils/share_code_utils.dart | 111 ++++++++++++
.../example_repository_test.mocks.dart | 80 ++++++---
.../states/example_selector_state_test.dart | 20 +--
.../states/example_selector_state_test.mocks.dart | 89 ++--------
.../playground/states/examples_state_test.dart | 31 +---
.../playground/states/mocks/example_mock.dart | 22 ++-
.../states/mocks/example_repository_mock.dart | 51 ++++++
.../example_repository_mock.mocks.dart} | 76 +++++---
.../playground/states/mocks/request_mock.dart | 2 +-
.../playground/states/playground_state_test.dart | 25 ++-
.../states/playground_state_test.mocks.dart | 197 +++++++++++++++++++++
71 files changed, 2079 insertions(+), 740 deletions(-)
diff --git a/playground/frontend/analysis_options.yaml b/playground/frontend/analysis_options.yaml
index fd91906eae8..340900ee193 100644
--- a/playground/frontend/analysis_options.yaml
+++ b/playground/frontend/analysis_options.yaml
@@ -100,7 +100,6 @@ linter:
use_if_null_to_convert_nulls_to_bools: true
use_is_even_rather_than_modulo: true
use_raw_strings: true
- use_setters_to_change_properties: true
use_to_and_as_if_applicable: true
#Turn off those on by default:
diff --git a/playground/frontend/lib/components/dropdown_button/dropdown_button.dart b/playground/frontend/lib/components/dropdown_button/dropdown_button.dart
index a554356c635..fa89fce72ff 100644
--- a/playground/frontend/lib/components/dropdown_button/dropdown_button.dart
+++ b/playground/frontend/lib/components/dropdown_button/dropdown_button.dart
@@ -19,26 +19,40 @@
import 'package:flutter/material.dart';
import 'package:playground/config/theme.dart';
import 'package:playground/constants/sizes.dart';
-import 'package:playground/modules/examples/models/selector_size_model.dart';
+import 'package:playground/utils/dropdown_utils.dart';
const int kAnimationDurationInMilliseconds = 80;
const Offset kAnimationBeginOffset = Offset(0.0, -0.02);
const Offset kAnimationEndOffset = Offset(0.0, 0.0);
-const double kAdditionalDyAlignment = 50.0;
+
+/// How to align the button and its dropdown.
+enum DropdownAlignment {
+ /// Align the left edges of the button and its dropdown.
+ left,
+
+ /// Align the right edges of the button and its dropdown.
+ right,
+}
class AppDropdownButton extends StatefulWidget {
final Widget buttonText;
final Widget Function(void Function()) createDropdown;
final double height;
final double width;
+ final Widget? leading;
+ final bool showArrow;
+ final DropdownAlignment dropdownAlign;
const AppDropdownButton({
- Key? key,
+ super.key,
required this.buttonText,
required this.createDropdown,
required this.height,
required this.width,
- }) : super(key: key);
+ this.leading,
+ this.showArrow = true,
+ this.dropdownAlign = DropdownAlignment.left,
+ });
@override
State<AppDropdownButton> createState() => _AppDropdownButtonState();
@@ -76,7 +90,7 @@ class _AppDropdownButtonState extends State<AppDropdownButton>
return Container(
height: kContainerHeight,
decoration: BoxDecoration(
- color: ThemeColors.of(context).greyColor,
+ color: ThemeColors.of(context).dropdownButton,
borderRadius: BorderRadius.circular(kSmBorderRadius),
),
child: TextButton(
@@ -88,8 +102,13 @@ class _AppDropdownButtonState extends State<AppDropdownButton>
alignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
+ if (widget.leading != null)
+ Padding(
+ padding: const EdgeInsets.only(right: kMdSpacing),
+ child: widget.leading,
+ ),
widget.buttonText,
- const Icon(Icons.keyboard_arrow_down),
+ if (widget.showArrow) const Icon(Icons.keyboard_arrow_down),
],
),
),
@@ -98,7 +117,11 @@ class _AppDropdownButtonState extends State<AppDropdownButton>
}
OverlayEntry createDropdown() {
- SelectorPositionModel posModel = findSelectorPositionData();
+ final dropdownOffset = findDropdownOffset(
+ alignment: widget.dropdownAlign,
+ key: selectorKey,
+ widgetWidth: widget.width,
+ );
return OverlayEntry(
builder: (context) {
@@ -115,8 +138,8 @@ class _AppDropdownButtonState extends State<AppDropdownButton>
),
),
Positioned(
- left: posModel.xAlignment,
- top: posModel.yAlignment + kAdditionalDyAlignment,
+ left: dropdownOffset.dx,
+ top: dropdownOffset.dy,
child: SlideTransition(
position: offsetAnimation,
child: Material(
@@ -126,7 +149,7 @@ class _AppDropdownButtonState extends State<AppDropdownButton>
height: widget.height,
width: widget.width,
decoration: BoxDecoration(
- color: Theme.of(context).backgroundColor,
+ color: ThemeColors.of(context).background,
borderRadius: BorderRadius.circular(kMdBorderRadius),
),
child: widget.createDropdown(_close),
@@ -140,16 +163,6 @@ class _AppDropdownButtonState extends State<AppDropdownButton>
);
}
- SelectorPositionModel findSelectorPositionData() {
- RenderBox? rBox =
- selectorKey.currentContext?.findRenderObject() as RenderBox;
- SelectorPositionModel positionModel = SelectorPositionModel(
- xAlignment: rBox.localToGlobal(Offset.zero).dx,
- yAlignment: rBox.localToGlobal(Offset.zero).dy,
- );
- return positionModel;
- }
-
void _close() {
animationController.reverse();
dropdown?.remove();
diff --git a/playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart b/playground/frontend/lib/components/horizonta_divider/horizontal_divider.dart
similarity index 65%
copy from playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart
copy to playground/frontend/lib/components/horizonta_divider/horizontal_divider.dart
index a505e4febd6..f935eade102 100644
--- a/playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart
+++ b/playground/frontend/lib/components/horizonta_divider/horizontal_divider.dart
@@ -17,24 +17,25 @@
*/
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/constants/sizes.dart';
-import 'package:provider/provider.dart';
-class ToggleThemeIconButton extends StatelessWidget {
- const ToggleThemeIconButton({Key? key}) : super(key: key);
+/// Replaces the Flutter's Divider which is buggy with HTML renderer,
+/// see https://github.com/flutter/flutter/issues/46339
+class HorizontalDivider extends StatelessWidget {
+ final double? indent;
+
+ const HorizontalDivider({
+ super.key,
+ this.indent,
+ });
@override
Widget build(BuildContext context) {
- return Consumer<ThemeProvider>(builder: (context, theme, child) {
- return IconButton(
- iconSize: kIconSizeLg,
- splashRadius: kIconButtonSplashRadius,
- icon: SvgPicture.asset(kThemeIconAsset),
- onPressed: theme.toggleTheme,
- );
- });
+ return Container(
+ height: kDividerHeight,
+ margin: EdgeInsets.fromLTRB(indent ?? 0, 0, indent ?? 0, 0),
+ color: ThemeColors.of(context).divider,
+ );
}
}
diff --git a/playground/frontend/lib/components/split_view/split_view.dart b/playground/frontend/lib/components/split_view/split_view.dart
index 922aea4e94c..06403d6759a 100644
--- a/playground/frontend/lib/components/split_view/split_view.dart
+++ b/playground/frontend/lib/components/split_view/split_view.dart
@@ -128,7 +128,7 @@ class _SplitViewState extends State<SplitView> {
child: Container(
width: _isHorizontal ? widget.dividerSize : double.infinity,
height: _isVertical ? widget.dividerSize : double.infinity,
- color: ThemeColors.of(context).greyColor,
+ color: ThemeColors.of(context).divider,
child: Center(
child: SvgPicture.asset(_isHorizontal
? kDragHorizontalIconAsset
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
index 1d55e600c0c..730b5b240b9 100644
--- a/playground/frontend/lib/components/toggle_theme_button/toggle_theme_button.dart
+++ b/playground/frontend/lib/components/toggle_theme_button/toggle_theme_button.dart
@@ -30,10 +30,10 @@ class ToggleThemeButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
- AppLocalizations appLocale = AppLocalizations.of(context)!;
+ final appLocale = AppLocalizations.of(context)!;
- return Consumer<ThemeProvider>(builder: (context, theme, child) {
- final text = theme.isDarkMode ? appLocale.lightMode : appLocale.darkMode;
+ return Consumer<ThemeSwitchNotifier>(builder: (context, notifier, child) {
+ final text = notifier.isDarkMode ? appLocale.lightMode : appLocale.darkMode;
return Padding(
padding: const EdgeInsets.symmetric(
@@ -44,9 +44,9 @@ class ToggleThemeButton extends StatelessWidget {
icon: SvgPicture.asset(kThemeIconAsset),
label: Text(text),
onPressed: () {
- theme.toggleTheme();
+ notifier.toggleTheme();
AnalyticsService.get(context)
- .trackClickToggleTheme(!theme.isDarkMode);
+ .trackClickToggleTheme(!notifier.isDarkMode);
},
),
);
diff --git a/playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart b/playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart
index a505e4febd6..f82270826fe 100644
--- a/playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart
+++ b/playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart
@@ -28,12 +28,12 @@ class ToggleThemeIconButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Consumer<ThemeProvider>(builder: (context, theme, child) {
+ return Consumer<ThemeSwitchNotifier>(builder: (context, notifier, child) {
return IconButton(
iconSize: kIconSizeLg,
splashRadius: kIconButtonSplashRadius,
icon: SvgPicture.asset(kThemeIconAsset),
- onPressed: theme.toggleTheme,
+ onPressed: notifier.toggleTheme,
);
});
}
diff --git a/playground/frontend/lib/config/theme.dart b/playground/frontend/lib/config/theme.dart
index 607135e0b4e..62a30f0082b 100644
--- a/playground/frontend/lib/config/theme.dart
+++ b/playground/frontend/lib/config/theme.dart
@@ -16,20 +16,46 @@
* 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 ThemeProvider extends ChangeNotifier {
+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();
}
@@ -53,6 +79,47 @@ class ThemeProvider extends ChangeNotifier {
}
}
+class ThemeSwitchNotifierProvider extends StatelessWidget {
+ final Widget child;
+
+ const ThemeSwitchNotifierProvider({
+ super.key,
+ required this.child,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return ChangeNotifierProvider<ThemeSwitchNotifier>(
+ create: (context) => ThemeSwitchNotifier()..init(),
+ child: Consumer<ThemeSwitchNotifier>(
+ 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<ThemeColors>.value(
+ value: data,
+ child: child,
+ );
+ }
+}
+
TextTheme createTextTheme(Color textColor) {
return getBaseFontTheme(
const TextTheme(
@@ -174,16 +241,42 @@ final kDarkTheme = ThemeData(
);
class ThemeColors {
+ final Color? _background;
+ final Color? _dropdownButton;
+
final bool isDark;
- static ThemeColors of(BuildContext context) {
- final theme = Provider.of<ThemeProvider>(context);
- return ThemeColors(theme.isDarkMode);
+ static ThemeColors of(BuildContext context, {bool listen = true}) {
+ return Provider.of<ThemeColors>(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,
+ );
}
- ThemeColors(this.isDark);
+ Color get dropdownButton =>
+ _dropdownButton ?? (isDark ? kDarkGrey : kLightGrey);
- Color get greyColor => isDark ? kDarkGrey : kLightGrey;
+ Color get divider => isDark ? kDarkGrey : kLightGrey;
Color get lightGreyColor => isDark ? kLightGrey1 : kLightGrey;
@@ -198,8 +291,9 @@ class ThemeColors {
Color get secondaryBackground =>
isDark ? kDarkSecondaryBackground : kLightSecondaryBackground;
- Color get primaryBackground =>
- isDark ? kDarkPrimaryBackground : kLightPrimaryBackground;
+ Color get background =>
+ _background ??
+ (isDark ? kDarkPrimaryBackground : kLightPrimaryBackground);
Color get code1 => isDark ? kDarkCode2 : kLightCode2;
diff --git a/playground/frontend/lib/constants/params.dart b/playground/frontend/lib/constants/params.dart
index d4d6e3fb8b0..82005b6e510 100644
--- a/playground/frontend/lib/constants/params.dart
+++ b/playground/frontend/lib/constants/params.dart
@@ -18,8 +18,12 @@
const kExampleParam = 'example';
const kIsEditableParam = 'editable';
-const kSourceCode = 'code';
const kContextLine = 'line';
-const kIsEmbedded = 'embedded';
const kQuickStartCategoryName = 'quick start';
+
+const _kIsEmbedded = 'embedded';
+
+bool isEmbedded() {
+ return Uri.base.toString().contains(_kIsEmbedded);
+}
diff --git a/playground/frontend/lib/constants/sizes.dart b/playground/frontend/lib/constants/sizes.dart
index 74f61ae307a..3d895aae285 100644
--- a/playground/frontend/lib/constants/sizes.dart
+++ b/playground/frontend/lib/constants/sizes.dart
@@ -61,3 +61,7 @@ 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 5eeb4421eb5..37f0bbbe41e 100644
--- a/playground/frontend/lib/l10n/app_en.arb
+++ b/playground/frontend/lib/l10n/app_en.arb
@@ -226,5 +226,25 @@
"result": "Result",
"@result": {
"description": "Name for the output tab"
+ },
+ "shareMyCode": "Share my code",
+ "@shareMyCode": {
+ "description": "Text for the share button"
+ },
+ "link": "Link",
+ "@link": {
+ "description": "Name of the Link tab in Share dropdown"
+ },
+ "embed": "Embed",
+ "@embed": {
+ "description": "Name of the Embed tab in Share dropdown"
+ },
+ "linkReady": "Link is ready! Anyone with this link can view your example.",
+ "@linkReady": {
+ "description": "Text that appears when user sees link to code sample"
+ },
+ "iframeCodeReady": "With this code you can embed Playground to your website.",
+ "@iframeCodeReady": {
+ "description": "Text that appears when user sees Playground iframe code"
}
-}
\ No newline at end of file
+}
diff --git a/playground/frontend/lib/modules/editor/components/editor_themes.dart b/playground/frontend/lib/modules/editor/components/editor_themes.dart
index e29f1d6bfe4..42c68905f96 100644
--- a/playground/frontend/lib/modules/editor/components/editor_themes.dart
+++ b/playground/frontend/lib/modules/editor/components/editor_themes.dart
@@ -29,7 +29,7 @@ CodeThemeData createTheme(ThemeColors colors) {
Map<String, TextStyle> _createThemeStyles(ThemeColors colors) {
return {
'root': TextStyle(
- backgroundColor: colors.primaryBackground,
+ backgroundColor: colors.background,
color: colors.textColor,
),
'comment': TextStyle(color: colors.codeComment),
@@ -62,6 +62,3 @@ Map<String, TextStyle> _createThemeStyles(ThemeColors colors) {
'strong': const TextStyle(fontWeight: FontWeight.bold),
};
}
-
-final kDarkCodeTheme = createTheme(ThemeColors(true));
-final kLightCodeTheme = createTheme(ThemeColors(false));
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
new file mode 100644
index 00000000000..9708a88208a
--- /dev/null
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/link_text_field.dart
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:playground/config/theme.dart';
+import 'package:playground/constants/font_weight.dart';
+import 'package:playground/constants/sizes.dart';
+
+const _kTextFieldMaxHeight = 45.0;
+
+class LinkTextField extends StatefulWidget {
+ final String text;
+
+ const LinkTextField({super.key, required this.text});
+
+ @override
+ State<LinkTextField> createState() => _LinkTextFieldState();
+}
+
+class _LinkTextFieldState extends State<LinkTextField> {
+ final textEditingController = TextEditingController();
+ bool _isPressed = false;
+
+ @override
+ initState() {
+ super.initState();
+ textEditingController.text = widget.text;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ decoration: BoxDecoration(
+ color: ThemeColors.of(context).dropdownButton,
+ borderRadius: BorderRadius.circular(kSmBorderRadius),
+ ),
+ child: Container(
+ margin: const EdgeInsets.symmetric(horizontal: kMdSpacing),
+ child: Center(
+ child: TextFormField(
+ controller: textEditingController,
+ decoration: InputDecoration(
+ constraints: const BoxConstraints(
+ maxHeight: _kTextFieldMaxHeight,
+ ),
+ border: InputBorder.none,
+ suffixIcon: _buildCopyButton(),
+ ),
+ readOnly: true,
+ style: TextStyle(
+ fontSize: kLabelFontSize,
+ fontWeight: kNormalWeight,
+ color: ThemeColors.of(context).primary,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ Widget _buildCopyButton() {
+ return MouseRegion(
+ cursor: SystemMouseCursors.click,
+ child: GestureDetector(
+ onTap: () async {
+ await _copyLinkText();
+ setState(() {
+ _isPressed = true;
+ });
+ },
+ child: _isPressed
+ ? const Icon(
+ Icons.check,
+ size: kIconSizeMd,
+ )
+ : const Icon(
+ Icons.file_copy_outlined,
+ size: kIconSizeSm,
+ ),
+ ),
+ );
+ }
+
+ Future<void> _copyLinkText() async {
+ await Clipboard.setData(ClipboardData(text: widget.text));
+ }
+}
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
new file mode 100644
index 00000000000..9355934e718
--- /dev/null
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_button.dart
@@ -0,0 +1,58 @@
+/*
+ * 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: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';
+
+const _kShareDropdownHeight = 140.0;
+const _kShareDropdownWidth = 460.0;
+const _kButtonColorOpacity = 0.2;
+
+class ShareButton extends StatelessWidget {
+ const ShareButton({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final appLocale = AppLocalizations.of(context)!;
+ final parentThemeData = ThemeColors.of(context);
+
+ final themeData = parentThemeData.copyWith(
+ background: parentThemeData.secondaryBackground,
+ dropdownButton: parentThemeData.primary.withOpacity(_kButtonColorOpacity),
+ );
+
+ return ThemeColorsProvider(
+ data: themeData,
+ child: AppDropdownButton(
+ buttonText: Text(appLocale.shareMyCode),
+ showArrow: false,
+ leading: Icon(
+ Icons.share_outlined,
+ color: ThemeColors.of(context).primary,
+ ),
+ height: _kShareDropdownHeight,
+ width: _kShareDropdownWidth,
+ dropdownAlign: DropdownAlignment.right,
+ createDropdown: (close) => const ShareDropdownBody(),
+ ),
+ );
+ }
+}
diff --git a/playground/frontend/lib/modules/output/components/output_header/output_header.dart b/playground/frontend/lib/modules/editor/components/share_dropdown/share_dropdown_body.dart
similarity index 50%
copy from playground/frontend/lib/modules/output/components/output_header/output_header.dart
copy to playground/frontend/lib/modules/editor/components/share_dropdown/share_dropdown_body.dart
index 95988ee6fcc..68a20837367 100644
--- a/playground/frontend/lib/modules/output/components/output_header/output_header.dart
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_dropdown_body.dart
@@ -17,40 +17,42 @@
*/
import 'package:flutter/material.dart';
-import 'package:playground/constants/sizes.dart';
-import 'package:playground/modules/output/components/output_header/output_placements.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 'output_tabs.dart';
+const _kTabsCount = 2;
-class OutputHeader extends StatelessWidget {
- final TabController tabController;
- final bool showOutputPlacements;
- final bool showGraph;
+class ShareDropdownBody extends StatefulWidget {
+ const ShareDropdownBody({super.key});
- const OutputHeader({
- Key? key,
- required this.tabController,
- this.showOutputPlacements = true,
- this.showGraph = true,
- }) : super(key: key);
+ @override
+ State<ShareDropdownBody> createState() => _ShareDropdownBodyState();
+}
+
+class _ShareDropdownBodyState extends State<ShareDropdownBody>
+ with SingleTickerProviderStateMixin {
+ late final tabController = TabController(vsync: this, length: _kTabsCount);
+
+ @override
+ void dispose() {
+ tabController.dispose();
+ super.dispose();
+ }
@override
Widget build(BuildContext context) {
- return SizedBox(
- height: 50,
- child: Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: kXlSpacing,
- vertical: kZeroSpacing,
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ TabHeader(
+ tabController: tabController,
+ tabsWidget: ShareTabsHeaders(tabController: tabController),
),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- OutputTabs(tabController: tabController, showGraph: showGraph),
- showOutputPlacements ? const OutputPlacements() : const SizedBox(),
- ],
+ Expanded(
+ child: ShareTabs(tabController: tabController),
),
- ),
+ ],
);
}
}
diff --git a/playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tab_body.dart
similarity index 62%
copy from playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart
copy to playground/frontend/lib/modules/editor/components/share_dropdown/share_tab_body.dart
index a505e4febd6..0055c9dc07b 100644
--- a/playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tab_body.dart
@@ -17,24 +17,28 @@
*/
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/constants/sizes.dart';
-import 'package:provider/provider.dart';
-class ToggleThemeIconButton extends StatelessWidget {
- const ToggleThemeIconButton({Key? key}) : super(key: key);
+class ShareTabBody extends StatelessWidget {
+ final List<Widget> children;
+
+ const ShareTabBody({
+ super.key,
+ required this.children,
+ });
@override
Widget build(BuildContext context) {
- return Consumer<ThemeProvider>(builder: (context, theme, child) {
- return IconButton(
- iconSize: kIconSizeLg,
- splashRadius: kIconButtonSplashRadius,
- icon: SvgPicture.asset(kThemeIconAsset),
- onPressed: theme.toggleTheme,
- );
- });
+ return Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: kXlSpacing,
+ ),
+ child: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: children,
+ ),
+ ),
+ );
}
}
diff --git a/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/example_share_tabs.dart b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/example_share_tabs.dart
new file mode 100644
index 00000000000..3a7747844e5
--- /dev/null
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/example_share_tabs.dart
@@ -0,0 +1,67 @@
+/*
+ * 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:playground/modules/editor/components/share_dropdown/link_text_field.dart';
+import 'package:playground/modules/editor/components/share_dropdown/share_tab_body.dart';
+import 'package:playground/utils/share_code_utils.dart';
+
+class ExampleShareTabs extends StatelessWidget {
+ final String examplePath;
+ final TabController tabController;
+
+ const ExampleShareTabs({
+ super.key,
+ required this.examplePath,
+ required this.tabController,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ final appLocale = AppLocalizations.of(context)!;
+
+ return TabBarView(
+ controller: tabController,
+ physics: const NeverScrollableScrollPhysics(),
+ children: [
+ ShareTabBody(
+ children: [
+ Text(appLocale.linkReady),
+ LinkTextField(
+ text: ShareCodeUtils.examplePathToPlaygroundUrl(
+ examplePath: examplePath,
+ view: PlaygroundView.standalone,
+ ).toString(),
+ ),
+ ],
+ ),
+ ShareTabBody(
+ children: [
+ Text(appLocale.iframeCodeReady),
+ LinkTextField(
+ text: ShareCodeUtils.examplePathToIframeCode(
+ examplePath: examplePath,
+ ),
+ ),
+ ],
+ ),
+ ],
+ );
+ }
+}
diff --git a/playground/frontend/lib/modules/output/components/output_header/output_header.dart b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/share_tabs.dart
similarity index 51%
copy from playground/frontend/lib/modules/output/components/output_header/output_header.dart
copy to playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/share_tabs.dart
index 95988ee6fcc..8c2e72948ae 100644
--- a/playground/frontend/lib/modules/output/components/output_header/output_header.dart
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/share_tabs.dart
@@ -17,39 +17,37 @@
*/
import 'package:flutter/material.dart';
-import 'package:playground/constants/sizes.dart';
-import 'package:playground/modules/output/components/output_header/output_placements.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:provider/provider.dart';
-import 'output_tabs.dart';
-
-class OutputHeader extends StatelessWidget {
+class ShareTabs extends StatelessWidget {
final TabController tabController;
- final bool showOutputPlacements;
- final bool showGraph;
- const OutputHeader({
- Key? key,
+ const ShareTabs({
+ super.key,
required this.tabController,
- this.showOutputPlacements = true,
- this.showGraph = true,
- }) : super(key: key);
+ });
@override
Widget build(BuildContext context) {
- return SizedBox(
- height: 50,
- child: Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: kXlSpacing,
- vertical: kZeroSpacing,
- ),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- OutputTabs(tabController: tabController, showGraph: showGraph),
- showOutputPlacements ? const OutputPlacements() : const SizedBox(),
- ],
- ),
+ return Container(
+ color: Theme.of(context).backgroundColor,
+ child: Consumer<PlaygroundState>(
+ builder: (context, playgroundState, _) {
+ if (playgroundState.isExampleChanged) {
+ return SnippetSaveAndShareTabs(
+ playgroundState: playgroundState,
+ tabController: tabController,
+ );
+ }
+
+ return ExampleShareTabs(
+ examplePath: playgroundState.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
new file mode 100644
index 00000000000..f8b606c81aa
--- /dev/null
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs/snippet_save_and_share_tabs.dart
@@ -0,0 +1,56 @@
+/*
+ * 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/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/modules/examples/repositories/models/shared_file_model.dart';
+import 'package:playground/pages/playground/states/playground_state.dart';
+
+class SnippetSaveAndShareTabs extends StatelessWidget {
+ final PlaygroundState playgroundState;
+ final TabController tabController;
+
+ const SnippetSaveAndShareTabs({
+ super.key,
+ required this.playgroundState,
+ required this.tabController,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return FutureBuilder(
+ future: playgroundState.exampleState.getSnippetId(
+ files: [SharedFile(code: playgroundState.source, isMain: true)],
+ sdk: playgroundState.sdk,
+ pipelineOptions: playgroundState.pipelineOptions,
+ ),
+ builder: (context, snapshot) {
+ if (!snapshot.hasData) {
+ return const LoadingIndicator(size: kLgLoadingIndicatorSize);
+ }
+
+ return ExampleShareTabs(
+ examplePath: snapshot.data.toString(),
+ tabController: tabController,
+ );
+ },
+ );
+ }
+}
diff --git a/playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs_headers.dart
similarity index 58%
copy from playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart
copy to playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs_headers.dart
index a505e4febd6..4d80b4309bd 100644
--- a/playground/frontend/lib/components/toggle_theme_button/toggle_theme_icon_button.dart
+++ b/playground/frontend/lib/modules/editor/components/share_dropdown/share_tabs_headers.dart
@@ -17,23 +17,34 @@
*/
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/constants/sizes.dart';
+import 'package:playground/pages/playground/states/playground_state.dart';
import 'package:provider/provider.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-class ToggleThemeIconButton extends StatelessWidget {
- const ToggleThemeIconButton({Key? key}) : super(key: key);
+const _width = 180.0;
+
+class ShareTabsHeaders extends StatelessWidget {
+ final TabController tabController;
+
+ const ShareTabsHeaders({
+ super.key,
+ required this.tabController,
+ });
@override
Widget build(BuildContext context) {
- return Consumer<ThemeProvider>(builder: (context, theme, child) {
- return IconButton(
- iconSize: kIconSizeLg,
- splashRadius: kIconButtonSplashRadius,
- icon: SvgPicture.asset(kThemeIconAsset),
- onPressed: theme.toggleTheme,
+ final appLocale = AppLocalizations.of(context)!;
+
+ return Consumer<PlaygroundState>(builder: (context, state, child) {
+ return SizedBox(
+ width: _width,
+ child: TabBar(
+ controller: tabController,
+ tabs: [
+ Text(appLocale.link),
+ Text(appLocale.embed),
+ ],
+ ),
);
});
}
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 643c4585d96..cf513333903 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
@@ -41,18 +41,16 @@ class ExpansionPanelItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Consumer2<PlaygroundState, ExampleState>(
- builder: (context, playgroundState, exampleState, child) => MouseRegion(
+ return Consumer<PlaygroundState>(
+ builder: (context, playgroundState, child) => MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () async {
if (playgroundState.selectedExample != example) {
- closeDropdown(exampleState);
+ _closeDropdown(playgroundState.exampleState);
AnalyticsService.get(context).trackSelectExample(example);
- final exampleWithInfo = await exampleState.loadExampleInfo(
- example,
- playgroundState.sdk,
- );
+ final exampleWithInfo =
+ await playgroundState.exampleState.loadExampleInfo(example);
playgroundState.setExample(exampleWithInfo);
}
},
@@ -82,7 +80,7 @@ class ExpansionPanelItem extends StatelessWidget {
);
}
- void closeDropdown(ExampleState exampleState) {
+ void _closeDropdown(ExampleState exampleState) {
animationController.reverse();
dropdown?.remove();
exampleState.changeSelectorVisibility();
diff --git a/playground/frontend/lib/modules/examples/example_selector.dart b/playground/frontend/lib/modules/examples/example_selector.dart
index 0e1c359a1d9..480852470a8 100644
--- a/playground/frontend/lib/modules/examples/example_selector.dart
+++ b/playground/frontend/lib/modules/examples/example_selector.dart
@@ -18,6 +18,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:playground/components/horizonta_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';
@@ -25,10 +26,10 @@ 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/modules/examples/models/selector_size_model.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:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -89,7 +90,7 @@ class _ExampleSelectorState extends State<ExampleSelector>
return Container(
height: kContainerHeight,
decoration: BoxDecoration(
- color: ThemeColors.of(context).greyColor,
+ color: ThemeColors.of(context).dropdownButton,
borderRadius: BorderRadius.circular(kSmBorderRadius),
),
child: Consumer<PlaygroundState>(
@@ -122,34 +123,35 @@ class _ExampleSelectorState extends State<ExampleSelector>
}
OverlayEntry createExamplesDropdown() {
- SelectorPositionModel posModel = findSelectorPositionData();
+ Offset dropdownOffset = findDropdownOffset(key: selectorKey);
return OverlayEntry(
builder: (context) {
return ChangeNotifierProvider<PopoverState>(
create: (context) => PopoverState(false),
builder: (context, state) {
- return Consumer2<ExampleState, PlaygroundState>(
- builder: (context, exampleState, playgroundState, child) => Stack(
+ return Consumer<PlaygroundState>(
+ builder: (context, playgroundState, child) => Stack(
children: [
OutsideClickHandler(
onTap: () {
- closeDropdown(exampleState);
+ _closeDropdown(playgroundState.exampleState);
// handle description dialogs
- Navigator.of(context, rootNavigator: true).popUntil((route) {
+ Navigator.of(context, rootNavigator: true)
+ .popUntil((route) {
return route.isFirst;
});
},
),
ChangeNotifierProvider(
create: (context) => ExampleSelectorState(
- exampleState,
playgroundState,
- exampleState.getCategories(playgroundState.sdk)!,
+ playgroundState.exampleState
+ .getCategories(playgroundState.sdk)!,
),
builder: (context, _) => Positioned(
- left: posModel.xAlignment,
- top: posModel.yAlignment + kAdditionalDyAlignment,
+ left: dropdownOffset.dx,
+ top: dropdownOffset.dy,
child: SlideTransition(
position: offsetAnimation,
child: Material(
@@ -159,12 +161,13 @@ class _ExampleSelectorState extends State<ExampleSelector>
width: kLgContainerWidth,
decoration: BoxDecoration(
color: Theme.of(context).backgroundColor,
- borderRadius: BorderRadius.circular(kMdBorderRadius),
+ borderRadius:
+ BorderRadius.circular(kMdBorderRadius),
+ ),
+ child: _buildDropdownContent(
+ context,
+ playgroundState,
),
- child: exampleState.sdkCategories == null ||
- playgroundState.selectedExample == null
- ? const LoadingIndicator(size: kContainerHeight)
- : _buildDropdownContent(context, playgroundState),
),
),
),
@@ -173,7 +176,7 @@ class _ExampleSelectorState extends State<ExampleSelector>
],
),
);
- }
+ },
);
},
);
@@ -183,6 +186,13 @@ class _ExampleSelectorState extends State<ExampleSelector>
BuildContext context,
PlaygroundState playgroundState,
) {
+ if (playgroundState.exampleState.sdkCategories == null ||
+ playgroundState.selectedExample == null) {
+ return const LoadingIndicator(
+ size: kMdLoadingIndicatorSize,
+ );
+ }
+
return Column(
children: [
SearchField(controller: textController),
@@ -193,12 +203,7 @@ class _ExampleSelectorState extends State<ExampleSelector>
animationController: animationController,
dropdown: examplesDropdown,
),
- Divider(
- height: kDividerHeight,
- color: ThemeColors.of(context).greyColor,
- indent: kLgSpacing,
- endIndent: kLgSpacing,
- ),
+ const HorizontalDivider(indent: kLgSpacing),
SizedBox(
width: double.infinity,
child: TextButton(
@@ -214,22 +219,12 @@ class _ExampleSelectorState extends State<ExampleSelector>
),
onPressed: () => launchUrl(Uri.parse(kAddExampleLink)),
),
- )
+ ),
],
);
}
- SelectorPositionModel findSelectorPositionData() {
- RenderBox? rBox =
- selectorKey.currentContext?.findRenderObject() as RenderBox;
- SelectorPositionModel positionModel = SelectorPositionModel(
- xAlignment: rBox.localToGlobal(Offset.zero).dx,
- yAlignment: rBox.localToGlobal(Offset.zero).dy,
- );
- return positionModel;
- }
-
- void closeDropdown(ExampleState exampleState) {
+ void _closeDropdown(ExampleState exampleState) {
animationController.reverse();
examplesDropdown?.remove();
exampleState.changeSelectorVisibility();
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/catalog_default_example_loading_descriptor.dart
similarity index 55%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/models/example_loading_descriptors/catalog_default_example_loading_descriptor.dart
index 27954f7ae22..0bdc18e01c7 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/catalog_default_example_loading_descriptor.dart
@@ -16,12 +16,25 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+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';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
+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;
+ }
}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/empty_example_loading_descriptor.dart
similarity index 56%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/models/example_loading_descriptors/empty_example_loading_descriptor.dart
index 27954f7ae22..5a7fa46dce0 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/empty_example_loading_descriptor.dart
@@ -16,12 +16,25 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+import 'package:playground/modules/examples/models/example_loading_descriptors/example_loading_descriptor.dart';
+import 'package:playground/modules/examples/models/example_origin.dart';
+import 'package:playground/modules/sdk/models/sdk.dart';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
+class EmptyExampleLoadingDescriptor extends ExampleLoadingDescriptor {
+ final SDK sdk;
+
+ const EmptyExampleLoadingDescriptor({
+ required this.sdk,
});
+
+ @override
+ ExampleOrigin get origin => ExampleOrigin.empty;
+
+ @override
+ int get hashCode => sdk.hashCode;
+
+ @override
+ bool operator ==(Object other) {
+ return other is EmptyExampleLoadingDescriptor && sdk == other.sdk;
+ }
}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/example_loading_descriptor.dart
similarity index 78%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/models/example_loading_descriptors/example_loading_descriptor.dart
index 27954f7ae22..539c3feaf20 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/example_loading_descriptor.dart
@@ -16,12 +16,13 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+import 'package:playground/modules/examples/models/example_origin.dart';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
- });
+abstract class ExampleLoadingDescriptor {
+ const ExampleLoadingDescriptor();
+
+ ExampleOrigin get origin;
+
+ @override
+ String toString() => '$origin';
}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/examples_loading_descriptor.dart
similarity index 56%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/models/example_loading_descriptors/examples_loading_descriptor.dart
index 27954f7ae22..84d6577bdaf 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/examples_loading_descriptor.dart
@@ -16,12 +16,26 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+import 'package:collection/collection.dart';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
+import 'package:playground/modules/examples/models/example_loading_descriptors/example_loading_descriptor.dart';
+
+class ExamplesLoadingDescriptor {
+ final List<ExampleLoadingDescriptor> descriptors;
+
+ const ExamplesLoadingDescriptor({
+ required this.descriptors,
});
+
+ @override
+ String toString() => descriptors.map((e) => e.toString()).join('_');
+
+ @override
+ int get hashCode => Object.hashAll(descriptors);
+
+ @override
+ bool operator ==(Object other) {
+ return other is ExamplesLoadingDescriptor &&
+ const ListEquality().equals(descriptors, other.descriptors);
+ }
}
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
new file mode 100644
index 00000000000..b0a07e6f312
--- /dev/null
+++ b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/examples_loading_descriptor_factory.dart
@@ -0,0 +1,79 @@
+/*
+ * 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/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/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';
+
+class ExamplesLoadingDescriptorFactory {
+ static ExamplesLoadingDescriptor fromUriParts({
+ required String path,
+ required Map<String, dynamic> params,
+ }) {
+ return _tryParseSingleExample(params) ??
+ _tryParseCatalogDefaultExample() ??
+ _oneEmptyWithDefaultSdk;
+ }
+
+ static ExamplesLoadingDescriptor? _tryParseSingleExample(
+ Map<String, dynamic> params,
+ ) {
+ final token = params[kExampleParam];
+ if (token is! String) {
+ return null;
+ }
+
+ return ExamplesLoadingDescriptor(
+ descriptors: [_parseSingleExample(token)],
+ );
+ }
+
+ static ExamplesLoadingDescriptor? _tryParseCatalogDefaultExample() {
+ if (isEmbedded()) {
+ return null;
+ }
+
+ return const ExamplesLoadingDescriptor(
+ descriptors: [CatalogDefaultExampleLoadingDescriptor(sdk: SDK.java)],
+ );
+ }
+
+ static ExampleLoadingDescriptor _parseSingleExample(String token) {
+ final tokenType = ExampleTokenType.fromToken(token);
+
+ switch (tokenType) {
+ case ExampleTokenType.standard:
+ return StandardExampleLoadingDescriptor(path: token);
+
+ case ExampleTokenType.userShared:
+ return UserSharedExampleLoadingDescriptor(snippetId: token);
+ }
+ }
+
+ static ExamplesLoadingDescriptor get _oneEmptyWithDefaultSdk {
+ return const ExamplesLoadingDescriptor(
+ descriptors: [EmptyExampleLoadingDescriptor(sdk: SDK.java)],
+ );
+ }
+}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/standard_example_loading_descriptor.dart
similarity index 55%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/models/example_loading_descriptors/standard_example_loading_descriptor.dart
index 27954f7ae22..8794fc02ac1 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/standard_example_loading_descriptor.dart
@@ -16,12 +16,27 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+import 'package:playground/modules/examples/models/example_loading_descriptors/example_loading_descriptor.dart';
+import 'package:playground/modules/examples/models/example_origin.dart';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
+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;
+ }
}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/user_shared_example_loading_descriptor.dart
similarity index 54%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/models/example_loading_descriptors/user_shared_example_loading_descriptor.dart
index 27954f7ae22..072445d04f0 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/models/example_loading_descriptors/user_shared_example_loading_descriptor.dart
@@ -16,12 +16,28 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+import 'package:playground/modules/examples/models/example_loading_descriptors/example_loading_descriptor.dart';
+import 'package:playground/modules/examples/models/example_origin.dart';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
+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;
+ }
}
diff --git a/playground/frontend/lib/modules/examples/models/example_model.dart b/playground/frontend/lib/modules/examples/models/example_model.dart
index d76b9c28efa..054dddb500a 100644
--- a/playground/frontend/lib/modules/examples/models/example_model.dart
+++ b/playground/frontend/lib/modules/examples/models/example_model.dart
@@ -16,6 +16,8 @@
* limitations under the License.
*/
+import 'package:playground/modules/sdk/models/sdk.dart';
+
enum ExampleType {
all,
example,
@@ -39,6 +41,7 @@ extension ExampleTypeToString on ExampleType {
}
class ExampleModel with Comparable<ExampleModel> {
+ final SDK sdk;
final ExampleType type;
final String name;
final String path;
@@ -53,6 +56,7 @@ class ExampleModel with Comparable<ExampleModel> {
String? graph;
ExampleModel({
+ required this.sdk,
required this.name,
required this.path,
required this.description,
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/models/example_origin.dart
similarity index 68%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/models/example_origin.dart
index 27954f7ae22..6be4b3b67f6 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/models/example_origin.dart
@@ -16,12 +16,25 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+import 'package:playground/modules/sdk/models/sdk.dart';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
- });
+enum ExampleOrigin {
+ empty,
+ standard,
+ userShared,
+ catalogDefault,
+ ;
+
+ static ExampleOrigin fromToken(String? token) {
+ if (token == null) {
+ return empty;
+ }
+
+ final sdk = SDK.tryParseExamplePath(token);
+ if (sdk != null) {
+ return standard;
+ }
+
+ return userShared;
+ }
}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/models/example_token_type.dart
similarity index 73%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/models/example_token_type.dart
index 27954f7ae22..789b1c3a179 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/models/example_token_type.dart
@@ -16,12 +16,19 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+import 'package:playground/modules/sdk/models/sdk.dart';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
- });
+enum ExampleTokenType {
+ standard,
+ userShared,
+ ;
+
+ static ExampleTokenType fromToken(String token) {
+ final sdk = SDK.tryParseExamplePath(token);
+ if (sdk != null) {
+ return standard;
+ }
+
+ return userShared;
+ }
}
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
index d63e42cba6a..039a567c5ef 100644
--- a/playground/frontend/lib/modules/examples/repositories/example_client/example_client.dart
+++ b/playground/frontend/lib/modules/examples/repositories/example_client/example_client.dart
@@ -17,18 +17,24 @@
*/
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<GetListOfExampleResponse> getListOfExamples(
GetListOfExamplesRequestWrapper request,
);
- Future<GetExampleCodeResponse> getExampleSource(GetExampleRequestWrapper request);
+ Future<GetExampleCodeResponse> getExampleSource(
+ GetExampleRequestWrapper request,
+ );
Future<GetExampleResponse> getDefaultExample(
GetExampleRequestWrapper request,
@@ -38,9 +44,23 @@ abstract class ExampleClient {
GetExampleRequestWrapper request,
);
- Future<OutputResponse> getExampleOutput(GetExampleRequestWrapper request);
+ Future<OutputResponse> getExampleOutput(
+ GetExampleRequestWrapper request,
+ );
+
+ Future<OutputResponse> getExampleLogs(
+ GetExampleRequestWrapper request,
+ );
+
+ Future<OutputResponse> getExampleGraph(
+ GetExampleRequestWrapper request,
+ );
- Future<OutputResponse> getExampleLogs(GetExampleRequestWrapper request);
+ Future<GetSnippetResponse> getSnippet(
+ GetSnippetRequestWrapper request,
+ );
- Future<OutputResponse> getExampleGraph(GetExampleRequestWrapper request);
+ Future<SaveSnippetResponse> 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
index 15d381e08e6..f4a11be58aa 100644
--- 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
@@ -29,6 +29,11 @@ import 'package:playground/modules/examples/repositories/models/get_example_requ
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';
@@ -63,8 +68,14 @@ class GrpcExampleClient implements ExampleClient {
() => _defaultClient
.getDefaultPrecompiledObject(
_getDefaultExampleRequestToGrpcRequest(request))
- .then((response) =>
- GetExampleResponse(_toExampleModel(response.precompiledObject))),
+ .then(
+ (response) => GetExampleResponse(
+ _toExampleModel(
+ request.sdk,
+ response.precompiledObject,
+ ),
+ ),
+ ),
);
}
@@ -76,8 +87,14 @@ class GrpcExampleClient implements ExampleClient {
() => _defaultClient
.getPrecompiledObject(
grpc.GetPrecompiledObjectRequest()..cloudPath = request.path)
- .then((response) =>
- GetExampleResponse(_toExampleModel(response.precompiledObject))),
+ .then(
+ (response) => GetExampleResponse(
+ _toExampleModel(
+ request.sdk,
+ response.precompiledObject,
+ ),
+ ),
+ ),
);
}
@@ -136,6 +153,38 @@ class GrpcExampleClient implements ExampleClient {
);
}
+ @override
+ Future<GetSnippetResponse> 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<SaveSnippetResponse> saveSnippet(
+ SaveSnippetRequestWrapper request,
+ ) {
+ return _runSafely(
+ () => _defaultClient
+ .saveSnippet(_saveSnippetRequestToGrpcRequest(request))
+ .then(
+ (response) => SaveSnippetResponse(
+ id: response.id,
+ ),
+ ),
+ );
+ }
+
Future<T> _runSafely<T>(Future<T> Function() invoke) {
try {
return invoke();
@@ -186,6 +235,21 @@ class GrpcExampleClient implements ExampleClient {
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:
@@ -239,7 +303,7 @@ class GrpcExampleClient implements ExampleClient {
List<CategoryModel> categoriesForSdk = [];
for (var category in sdkMap.categories) {
List<ExampleModel> examples = category.precompiledObjects
- .map((example) => _toExampleModel(example))
+ .map((example) => _toExampleModel(sdk, example))
.toList()
..sort();
categoriesForSdk.add(CategoryModel(
@@ -253,8 +317,9 @@ class GrpcExampleClient implements ExampleClient {
return sdkCategoriesMap;
}
- ExampleModel _toExampleModel(grpc.PrecompiledObject example) {
+ ExampleModel _toExampleModel(SDK sdk, grpc.PrecompiledObject example) {
return ExampleModel(
+ sdk: sdk,
name: example.name,
description: example.description,
type: _exampleTypeFromString(example.type),
@@ -265,4 +330,37 @@ class GrpcExampleClient implements ExampleClient {
link: example.link,
);
}
+
+ List<SharedFile> _convertToSharedFileList(
+ List<grpc.SnippetFile> snippetFileList,
+ ) {
+ final sharedFilesList = <SharedFile>[];
+
+ for (grpc.SnippetFile item in snippetFileList) {
+ sharedFilesList.add(SharedFile(
+ code: item.content,
+ isMain: item.isMain,
+ name: item.name,
+ ));
+ }
+
+ return sharedFilesList;
+ }
+
+ List<grpc.SnippetFile> _convertToSnippetFileList(
+ List<SharedFile> sharedFilesList,
+ ) {
+ final snippetFileList = <grpc.SnippetFile>[];
+
+ 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
index ef4c4e25145..65c09f885fb 100644
--- a/playground/frontend/lib/modules/examples/repositories/example_repository.dart
+++ b/playground/frontend/lib/modules/examples/repositories/example_repository.dart
@@ -19,8 +19,11 @@
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 {
@@ -44,7 +47,9 @@ class ExampleRepository {
return result.example;
}
- Future<String> getExampleSource(GetExampleRequestWrapper request) async {
+ Future<String> getExampleSource(
+ GetExampleRequestWrapper request,
+ ) async {
final result = await _client.getExampleSource(request);
return result.code;
}
@@ -76,4 +81,18 @@ class ExampleRepository {
final result = await _client.getExample(request);
return result.example;
}
+
+ Future<GetSnippetResponse> getSnippet(
+ GetSnippetRequestWrapper request,
+ ) async {
+ final result = await _client.getSnippet(request);
+ return result;
+ }
+
+ Future<String> saveSnippet(
+ SaveSnippetRequestWrapper request,
+ ) async {
+ final result = await _client.saveSnippet(request);
+ return result.id;
+ }
}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/repositories/models/get_snippet_request.dart
similarity index 82%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/repositories/models/get_snippet_request.dart
index 27954f7ae22..4319884981d 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/repositories/models/get_snippet_request.dart
@@ -16,12 +16,10 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+class GetSnippetRequestWrapper {
+ final String id;
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
+ const GetSnippetRequestWrapper({
+ required this.id,
});
}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/repositories/models/get_snippet_response.dart
similarity index 68%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/repositories/models/get_snippet_response.dart
index 27954f7ae22..167f725a5fb 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/repositories/models/get_snippet_response.dart
@@ -16,12 +16,17 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+import 'package:playground/modules/examples/repositories/models/shared_file_model.dart';
+import 'package:playground/modules/sdk/models/sdk.dart';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
+class GetSnippetResponse {
+ final List<SharedFile> files;
+ final SDK sdk;
+ final String pipelineOptions;
+
+ const GetSnippetResponse({
+ required this.files,
+ required this.sdk,
+ required this.pipelineOptions,
});
}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/repositories/models/save_snippet_request.dart
similarity index 68%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/repositories/models/save_snippet_request.dart
index 27954f7ae22..c29ee4230f6 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/repositories/models/save_snippet_request.dart
@@ -16,12 +16,17 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+import 'package:playground/modules/examples/repositories/models/shared_file_model.dart';
+import 'package:playground/modules/sdk/models/sdk.dart';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
+class SaveSnippetRequestWrapper {
+ final List<SharedFile> files;
+ final SDK sdk;
+ final String pipelineOptions;
+
+ const SaveSnippetRequestWrapper({
+ required this.files,
+ required this.sdk,
+ required this.pipelineOptions,
});
}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/repositories/models/save_snippet_response.dart
similarity index 82%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/repositories/models/save_snippet_response.dart
index 27954f7ae22..d0379bb73b6 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/repositories/models/save_snippet_response.dart
@@ -16,12 +16,10 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+class SaveSnippetResponse {
+ final String id;
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
+ const SaveSnippetResponse({
+ required this.id,
});
}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/modules/examples/repositories/models/shared_file_model.dart
similarity index 82%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/modules/examples/repositories/models/shared_file_model.dart
index 27954f7ae22..7a63f2a91cd 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/modules/examples/repositories/models/shared_file_model.dart
@@ -16,12 +16,14 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+class SharedFile {
+ final String code;
+ final bool isMain;
+ final String name;
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
+ const SharedFile({
+ required this.code,
+ required this.isMain,
+ this.name = '',
});
}
diff --git a/playground/frontend/lib/modules/output/components/output.dart b/playground/frontend/lib/modules/output/components/output.dart
index 1f6dac63837..b99692749cb 100644
--- a/playground/frontend/lib/modules/output/components/output.dart
+++ b/playground/frontend/lib/modules/output/components/output.dart
@@ -18,7 +18,9 @@
import 'package:flutter/material.dart';
import 'package:playground/modules/output/components/output_area.dart';
-import 'package:playground/modules/output/components/output_header/output_header.dart';
+import 'package:playground/modules/output/components/output_header/output_placements.dart';
+import 'package:playground/modules/output/components/output_header/output_tabs.dart';
+import 'package:playground/modules/output/components/output_header/tab_header.dart';
import 'package:playground/pages/playground/states/playground_state.dart';
const kTabsCount = 2;
@@ -70,10 +72,18 @@ class _OutputState extends State<Output> with SingleTickerProviderStateMixin {
Widget build(BuildContext context) {
return Column(
children: [
- OutputHeader(
- tabController: tabController,
- showOutputPlacements: !widget.isEmbedded,
- showGraph: widget.showGraph,
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ TabHeader(
+ tabController: tabController,
+ tabsWidget: OutputTabs(
+ tabController: tabController,
+ showGraph: widget.showGraph,
+ ),
+ ),
+ const OutputPlacements(),
+ ],
),
Expanded(
child: OutputArea(
diff --git a/playground/frontend/lib/modules/output/components/output_header/output_placements.dart b/playground/frontend/lib/modules/output/components/output_header/output_placements.dart
index 09d62198d94..f8eaf571024 100644
--- a/playground/frontend/lib/modules/output/components/output_header/output_placements.dart
+++ b/playground/frontend/lib/modules/output/components/output_header/output_placements.dart
@@ -31,27 +31,30 @@ class OutputPlacements extends StatelessWidget {
Widget build(BuildContext context) {
return Consumer<OutputPlacementState>(
builder: (context, state, child) {
- return Wrap(
- spacing: kMdSpacing,
- children: OutputPlacement.values
- .map(
- (placement) => Semantics(
- label:
- '${AppLocalizations.of(context)!.outputPlacementSemantic}'
- ' ${placement.name(context)}',
- child: IconButton(
- splashRadius: kIconButtonSplashRadius,
- icon: SvgPicture.asset(
- placement.icon,
- color: state.placement == placement
- ? Theme.of(context).primaryColor
- : null,
+ return Padding(
+ padding: const EdgeInsets.symmetric(horizontal: kXlSpacing),
+ child: Wrap(
+ spacing: kMdSpacing,
+ children: OutputPlacement.values
+ .map(
+ (placement) => Semantics(
+ label:
+ '${AppLocalizations.of(context)!.outputPlacementSemantic}'
+ ' ${placement.name(context)}',
+ child: IconButton(
+ splashRadius: kIconButtonSplashRadius,
+ icon: SvgPicture.asset(
+ placement.icon,
+ color: state.placement == placement
+ ? Theme.of(context).primaryColor
+ : null,
+ ),
+ onPressed: () => state.setPlacement(placement),
),
- onPressed: () => state.setPlacement(placement),
),
- ),
- )
- .toList(),
+ )
+ .toList(),
+ ),
);
},
);
diff --git a/playground/frontend/lib/modules/output/components/output_header/output_header.dart b/playground/frontend/lib/modules/output/components/output_header/tab_header.dart
similarity index 66%
rename from playground/frontend/lib/modules/output/components/output_header/output_header.dart
rename to playground/frontend/lib/modules/output/components/output_header/tab_header.dart
index 95988ee6fcc..dbf60b30f8a 100644
--- a/playground/frontend/lib/modules/output/components/output_header/output_header.dart
+++ b/playground/frontend/lib/modules/output/components/output_header/tab_header.dart
@@ -18,21 +18,18 @@
import 'package:flutter/material.dart';
import 'package:playground/constants/sizes.dart';
-import 'package:playground/modules/output/components/output_header/output_placements.dart';
-import 'output_tabs.dart';
+const kHeaderHeight = 50.0;
-class OutputHeader extends StatelessWidget {
+class TabHeader extends StatelessWidget {
final TabController tabController;
- final bool showOutputPlacements;
- final bool showGraph;
+ final Widget tabsWidget;
- const OutputHeader({
- Key? key,
+ const TabHeader({
+ super.key,
required this.tabController,
- this.showOutputPlacements = true,
- this.showGraph = true,
- }) : super(key: key);
+ required this.tabsWidget,
+ });
@override
Widget build(BuildContext context) {
@@ -43,13 +40,7 @@ class OutputHeader extends StatelessWidget {
horizontal: kXlSpacing,
vertical: kZeroSpacing,
),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- OutputTabs(tabController: tabController, showGraph: showGraph),
- showOutputPlacements ? const OutputPlacements() : const SizedBox(),
- ],
- ),
+ child: tabsWidget,
),
);
}
diff --git a/playground/frontend/lib/modules/sdk/components/sdk_selector.dart b/playground/frontend/lib/modules/sdk/components/sdk_selector.dart
index 45cacfc5622..4564d0879c9 100644
--- a/playground/frontend/lib/modules/sdk/components/sdk_selector.dart
+++ b/playground/frontend/lib/modules/sdk/components/sdk_selector.dart
@@ -23,7 +23,7 @@ import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/examples/models/example_model.dart';
import 'package:playground/modules/sdk/components/sdk_selector_row.dart';
import 'package:playground/modules/sdk/models/sdk.dart';
-import 'package:playground/pages/playground/states/examples_state.dart';
+import 'package:playground/pages/playground/states/playground_state.dart';
import 'package:provider/provider.dart';
typedef SetSdk = void Function(SDK sdk);
@@ -62,15 +62,16 @@ class SDKSelector extends StatelessWidget {
...SDK.values.map((SDK value) {
return SizedBox(
width: double.infinity,
- child: Consumer<ExampleState>(
+ child: Consumer<PlaygroundState>(
builder: (context, state, child) => SdkSelectorRow(
sdk: value,
onSelect: () {
close();
setSdk(value);
setExample(
- state.defaultExamplesMap[value] ??
+ state.exampleState.defaultExamplesMap[value] ??
ExampleModel(
+ sdk: value,
name: kEmptyExampleName,
path: '',
description: '',
diff --git a/playground/frontend/lib/modules/sdk/models/sdk.dart b/playground/frontend/lib/modules/sdk/models/sdk.dart
index 17283fcb0b1..bb5eaa2af1b 100644
--- a/playground/frontend/lib/modules/sdk/models/sdk.dart
+++ b/playground/frontend/lib/modules/sdk/models/sdk.dart
@@ -28,6 +28,33 @@ enum SDK {
go,
python,
scio,
+ ;
+
+ /// A temporary solution while we wait for the backend to add
+ /// sdk in example responses.
+ static SDK? tryParseExamplePath(String? path) {
+ if (path == null) {
+ return null;
+ }
+
+ if (path.startsWith('SDK_JAVA')) {
+ return java;
+ }
+
+ if (path.startsWith('SDK_GO')) {
+ return go;
+ }
+
+ if (path.startsWith('SDK_PYTHON')) {
+ return python;
+ }
+
+ if (path.startsWith('SDK_SCIO')) {
+ return scio;
+ }
+
+ return null;
+ }
}
extension SDKToString on SDK {
diff --git a/playground/frontend/lib/pages/playground/components/editor_textarea_wrapper.dart b/playground/frontend/lib/pages/playground/components/editor_textarea_wrapper.dart
index a5c2115fed0..2a8765b6302 100644
--- a/playground/frontend/lib/pages/playground/components/editor_textarea_wrapper.dart
+++ b/playground/frontend/lib/pages/playground/components/editor_textarea_wrapper.dart
@@ -22,6 +22,7 @@ import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/analytics/analytics_service.dart';
import 'package:playground/modules/editor/components/editor_textarea.dart';
import 'package:playground/modules/editor/components/run_button.dart';
+import 'package:playground/modules/editor/components/share_dropdown/share_button.dart';
import 'package:playground/modules/examples/components/description_popover/description_popover_button.dart';
import 'package:playground/modules/examples/components/multifile_popover/multifile_popover_button.dart';
import 'package:playground/modules/notifications/components/notification.dart';
@@ -79,6 +80,11 @@ class CodeTextAreaWrapper extends StatelessWidget {
),
),
],
+ Semantics(
+ container: true,
+ child: const ShareButton(),
+ ),
+ const SizedBox(width: kLgSpacing),
Semantics(
container: true,
child: RunButton(
@@ -92,7 +98,8 @@ class CodeTextAreaWrapper extends StatelessWidget {
(_) => NotificationManager.showError(
context,
AppLocalizations.of(context)!.runCode,
- AppLocalizations.of(context)!.cancelExecution,
+ AppLocalizations.of(context)!
+ .cancelExecution,
),
);
},
diff --git a/playground/frontend/lib/pages/playground/components/feedback/feedback_dropdown_content.dart b/playground/frontend/lib/pages/playground/components/feedback/feedback_dropdown_content.dart
index d94b5246336..e6694239b06 100644
--- a/playground/frontend/lib/pages/playground/components/feedback/feedback_dropdown_content.dart
+++ b/playground/frontend/lib/pages/playground/components/feedback/feedback_dropdown_content.dart
@@ -17,13 +17,13 @@
*/
import 'package:flutter/material.dart';
+import 'package:playground/components/horizonta_divider/horizontal_divider.dart';
import 'package:playground/config/theme.dart';
import 'package:playground/constants/font_weight.dart';
import 'package:playground/constants/fonts.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/analytics/analytics_service.dart';
-
-import 'feedback_dropdown_icon_button.dart';
+import 'package:playground/pages/playground/components/feedback/feedback_dropdown_icon_button.dart';
const double kTextFieldWidth = 365.0;
const double kTextFieldHeight = 68.0;
@@ -124,7 +124,7 @@ class FeedbackDropdownContent extends StatelessWidget {
],
),
),
- const Divider(height: kDividerHeight),
+ const HorizontalDivider(),
Padding(
padding: const EdgeInsets.only(
top: kXlSpacing,
@@ -171,10 +171,10 @@ class FeedbackDropdownContent extends StatelessWidget {
},
child: const Text(kSendFeedbackButtonTitle),
),
- )
+ ),
],
),
- )
+ ),
],
),
);
diff --git a/playground/frontend/lib/pages/playground/components/playground_page_body.dart b/playground/frontend/lib/pages/playground/components/playground_page_body.dart
index 3b005d2a979..8a723982ed4 100644
--- a/playground/frontend/lib/pages/playground/components/playground_page_body.dart
+++ b/playground/frontend/lib/pages/playground/components/playground_page_body.dart
@@ -70,11 +70,11 @@ class PlaygroundPageBody extends StatelessWidget {
Widget getVerticalSeparator(BuildContext context) => Container(
width: kMdSpacing,
- color: ThemeColors.of(context).greyColor,
+ color: ThemeColors.of(context).divider,
);
Widget getHorizontalSeparator(BuildContext context) => Container(
height: kMdSpacing,
- color: ThemeColors.of(context).greyColor,
+ color: ThemeColors.of(context).divider,
);
}
diff --git a/playground/frontend/lib/pages/playground/components/playground_page_providers.dart b/playground/frontend/lib/pages/playground/components/playground_page_providers.dart
index beeb95e184b..e61da539b3a 100644
--- a/playground/frontend/lib/pages/playground/components/playground_page_providers.dart
+++ b/playground/frontend/lib/pages/playground/components/playground_page_providers.dart
@@ -17,15 +17,14 @@
*/
import 'package:flutter/material.dart';
-import 'package:playground/constants/params.dart';
import 'package:playground/modules/analytics/analytics_service.dart';
import 'package:playground/modules/analytics/google_analytics_service.dart';
import 'package:playground/modules/editor/repository/code_repository/code_client/grpc_code_client.dart';
import 'package:playground/modules/editor/repository/code_repository/code_repository.dart';
-import 'package:playground/modules/examples/models/example_model.dart';
import 'package:playground/modules/examples/repositories/example_client/grpc_example_client.dart';
import 'package:playground/modules/examples/repositories/example_repository.dart';
import 'package:playground/modules/output/models/output_placement_state.dart';
+import 'package:playground/pages/playground/states/example_loaders/examples_loader.dart';
import 'package:playground/pages/playground/states/examples_state.dart';
import 'package:playground/pages/playground/states/feedback_state.dart';
import 'package:playground/pages/playground/states/playground_state.dart';
@@ -48,19 +47,12 @@ class PlaygroundPageProviders extends StatelessWidget {
return MultiProvider(
providers: [
Provider<AnalyticsService>(create: (context) => GoogleAnalyticsService()),
- ChangeNotifierProvider<ExampleState>(
- create: (context) => ExampleState(kExampleRepository)..init(),
- ),
- ChangeNotifierProxyProvider<ExampleState, PlaygroundState>(
- create: (context) => PlaygroundState(codeRepository: kCodeRepository),
- update: (context, exampleState, playground) {
- if (playground == null) {
- return PlaygroundState(codeRepository: kCodeRepository);
- }
-
- _onExampleStateChanged(exampleState, playground);
- return playground;
- },
+ ChangeNotifierProvider<PlaygroundState>(
+ create: (context) => PlaygroundState(
+ examplesLoader: ExamplesLoader(),
+ exampleState: ExampleState(kExampleRepository)..init(),
+ codeRepository: kCodeRepository,
+ ),
),
ChangeNotifierProvider<OutputPlacementState>(
create: (context) => OutputPlacementState(),
@@ -72,110 +64,4 @@ class PlaygroundPageProviders extends StatelessWidget {
child: child,
);
}
-
- void _onExampleStateChanged(
- ExampleState exampleState,
- PlaygroundState playgroundState,
- ) {
- // This property currently doubles as a flag of initialization
- // because it is initialized when an example is ready
- // and is filled with a null-object if not showing any example.
- //
- // TODO: Add a dedicated flag of initialization or make
- // PlaygroundState listen for examples and init itself.
- if (playgroundState.selectedExample != null) {
- return; // Already initialized.
- }
-
- if (_isEmbedded()) {
- _initEmbedded(exampleState, playgroundState);
- } else {
- _initNonEmbedded(exampleState, playgroundState);
- }
- }
-
- bool _isEmbedded() {
- return Uri.base.toString().contains(kIsEmbedded);
- }
-
- Future<void> _initEmbedded(
- ExampleState exampleState,
- PlaygroundState playgroundState,
- ) async {
- final example = _getEmbeddedExample();
-
- if (example.path.isEmpty) {
- String source = Uri.base.queryParameters[kSourceCode] ?? '';
- example.setSource(source);
- playgroundState.setExample(example);
- } else {
- final loadedExample = await exampleState.getExample(
- example.path,
- playgroundState.sdk,
- );
-
- final exampleWithInfo = await exampleState.loadExampleInfo(
- loadedExample,
- playgroundState.sdk,
- );
-
- playgroundState.setExample(exampleWithInfo);
- }
- }
-
- ExampleModel _getEmbeddedExample() {
- final examplePath = Uri.base.queryParameters[kExampleParam];
-
- return ExampleModel(
- name: 'Embedded_Example',
- path: examplePath ?? '',
- description: '',
- type: ExampleType.example,
- );
- }
-
- Future<void> _initNonEmbedded(
- ExampleState exampleState,
- PlaygroundState playgroundState,
- ) async {
- await exampleState.loadDefaultExamplesIfNot();
-
- final example = await _getExample(exampleState, playgroundState);
-
- if (example == null) {
- return;
- }
-
- final exampleWithInfo = await exampleState.loadExampleInfo(
- example,
- playgroundState.sdk,
- );
-
- playgroundState.setExample(exampleWithInfo);
- }
-
- Future<ExampleModel?> _getExample(
- ExampleState exampleState,
- PlaygroundState playground,
- ) async {
- final examplePath = Uri.base.queryParameters[kExampleParam];
-
- if (examplePath?.isEmpty ?? true) {
- return exampleState.defaultExamplesMap[playground.sdk];
- }
-
- final allExamples = exampleState.sdkCategories?.values
- .expand((sdkCategory) => sdkCategory.map((e) => e.examples))
- .expand((element) => element)
- .toList();
-
- if (allExamples?.isEmpty ?? true) {
- return null;
- }
-
- return allExamples?.firstWhere(
- (example) => example.path == examplePath,
- orElse: () => exampleState.defaultExample!,
- );
- }
}
diff --git a/playground/frontend/lib/pages/playground/playground_page.dart b/playground/frontend/lib/pages/playground/playground_page.dart
index 75725c2d59b..ee4029cbda6 100644
--- a/playground/frontend/lib/pages/playground/playground_page.dart
+++ b/playground/frontend/lib/pages/playground/playground_page.dart
@@ -33,7 +33,6 @@ import 'package:playground/pages/playground/components/close_listener_nonweb.dar
import 'package:playground/pages/playground/components/more_actions.dart';
import 'package:playground/pages/playground/components/playground_page_body.dart';
import 'package:playground/pages/playground/components/playground_page_footer.dart';
-import 'package:playground/pages/playground/states/examples_state.dart';
import 'package:playground/pages/playground/states/playground_state.dart';
import 'package:provider/provider.dart';
@@ -55,14 +54,10 @@ class PlaygroundPage extends StatelessWidget {
spacing: kXlSpacing,
children: [
const Logo(),
- Consumer<ExampleState>(
- builder: (context, state, child) {
- return ExampleSelector(
- changeSelectorVisibility:
- state.changeSelectorVisibility,
- isSelectorOpened: state.isSelectorOpened,
- );
- },
+ ExampleSelector(
+ changeSelectorVisibility:
+ state.exampleState.changeSelectorVisibility,
+ isSelectorOpened: state.exampleState.isSelectorOpened,
),
SDKSelector(
sdk: state.sdk,
diff --git a/playground/frontend/lib/pages/playground/states/example_loaders/catalog_default_example_loader.dart b/playground/frontend/lib/pages/playground/states/example_loaders/catalog_default_example_loader.dart
new file mode 100644
index 00000000000..e07d4cb67d6
--- /dev/null
+++ b/playground/frontend/lib/pages/playground/states/example_loaders/catalog_default_example_loader.dart
@@ -0,0 +1,48 @@
+/*
+ * 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/catalog_default_example_loading_descriptor.dart';
+import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground/pages/playground/states/example_loaders/example_loader.dart';
+import 'package:playground/pages/playground/states/examples_state.dart';
+
+class CatalogDefaultExampleLoader extends ExampleLoader {
+ final CatalogDefaultExampleLoadingDescriptor descriptor;
+ final ExampleState exampleState;
+
+ const CatalogDefaultExampleLoader({
+ required this.descriptor,
+ required this.exampleState,
+ });
+
+ @override
+ Future<ExampleModel> get future async {
+ if (!exampleState.hasExampleCatalog) {
+ throw Exception('Default example requires a catalog in ExampleState');
+ }
+
+ await exampleState.loadDefaultExamplesIfNot();
+ final result = exampleState.defaultExamplesMap[descriptor.sdk];
+
+ if (result == null) {
+ throw Exception('Default example not found for $descriptor');
+ }
+
+ return result;
+ }
+}
diff --git a/playground/frontend/test/pages/playground/states/mocks/example_mock.dart b/playground/frontend/lib/pages/playground/states/example_loaders/empty_example_loader.dart
similarity index 52%
copy from playground/frontend/test/pages/playground/states/mocks/example_mock.dart
copy to playground/frontend/lib/pages/playground/states/example_loaders/empty_example_loader.dart
index 0be09e915f0..5552d31fb45 100644
--- a/playground/frontend/test/pages/playground/states/mocks/example_mock.dart
+++ b/playground/frontend/lib/pages/playground/states/example_loaders/empty_example_loader.dart
@@ -16,38 +16,26 @@
* limitations under the License.
*/
+import 'package:playground/modules/examples/models/example_loading_descriptors/empty_example_loading_descriptor.dart';
import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground/pages/playground/states/example_loaders/example_loader.dart';
+import 'package:playground/pages/playground/states/examples_state.dart';
-final ExampleModel exampleMock1 = ExampleModel(
- source: 'ex1',
- name: 'Example',
- type: ExampleType.example,
- description: 'description',
- path: 'SDK/Category/Name',
-);
+class EmptyExampleLoader extends ExampleLoader {
+ final EmptyExampleLoadingDescriptor descriptor;
+ final ExampleState exampleState;
-final ExampleModel exampleMock2 = ExampleModel(
- source: 'ex2',
- name: 'Kata',
- type: ExampleType.kata,
- description: 'description',
- path: 'SDK/Category/Name',
-);
+ const EmptyExampleLoader({
+ required this.descriptor,
+ required this.exampleState,
+ });
-final ExampleModel exampleWithoutSourceMock = ExampleModel(
- name: 'Test example',
- type: ExampleType.example,
- description: 'description',
- path: 'SDK/Category/Name',
-);
-
-final ExampleModel exampleWithAllAdditionsMock = ExampleModel(
- name: 'Test example',
- type: ExampleType.example,
- description: 'description',
- path: 'SDK/Category/Name',
- source: 'test outputs',
- outputs: 'test outputs',
- logs: 'test outputs',
- graph: 'test outputs',
-);
+ @override
+ Future<ExampleModel> get future async => ExampleModel(
+ sdk: descriptor.sdk,
+ name: 'Embedded_Example',
+ path: '',
+ description: '',
+ type: ExampleType.example,
+ );
+}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/pages/playground/states/example_loaders/example_loader.dart
similarity index 81%
copy from playground/frontend/lib/modules/examples/models/selector_size_model.dart
copy to playground/frontend/lib/pages/playground/states/example_loaders/example_loader.dart
index 27954f7ae22..9c6b256683c 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/pages/playground/states/example_loaders/example_loader.dart
@@ -16,12 +16,10 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+import 'package:playground/modules/examples/models/example_model.dart';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
- });
+abstract class ExampleLoader {
+ const ExampleLoader();
+
+ Future<ExampleModel> get future;
}
diff --git a/playground/frontend/lib/pages/playground/states/example_loaders/examples_loader.dart b/playground/frontend/lib/pages/playground/states/example_loaders/examples_loader.dart
new file mode 100644
index 00000000000..f9ae8a7058b
--- /dev/null
+++ b/playground/frontend/lib/pages/playground/states/example_loaders/examples_loader.dart
@@ -0,0 +1,87 @@
+/*
+ * 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/catalog_default_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/pages/playground/states/example_loaders/catalog_default_example_loader.dart';
+import 'package:playground/pages/playground/states/example_loaders/empty_example_loader.dart';
+import 'package:playground/pages/playground/states/example_loaders/example_loader.dart';
+import 'package:playground/pages/playground/states/example_loaders/standard_example_loader.dart';
+import 'package:playground/pages/playground/states/example_loaders/user_shared_example_loader.dart';
+import 'package:playground/pages/playground/states/playground_state.dart';
+
+class ExamplesLoader {
+ PlaygroundState? _playgroundState;
+ ExamplesLoadingDescriptor? _descriptor;
+
+ void setPlaygroundState(PlaygroundState value) {
+ _playgroundState = value;
+ }
+
+ Future<void> load(ExamplesLoadingDescriptor descriptor) async {
+ if (_descriptor == descriptor) {
+ return;
+ }
+
+ _descriptor = descriptor;
+ await Future.wait(descriptor.descriptors.map(_loadOne));
+ }
+
+ Future<void> _loadOne(ExampleLoadingDescriptor descriptor) async {
+ final example = await _getOneLoader(descriptor).future;
+ _playgroundState!.setExample(example);
+ }
+
+ ExampleLoader _getOneLoader(ExampleLoadingDescriptor descriptor) {
+ final exampleState = _playgroundState!.exampleState;
+
+ if (descriptor is CatalogDefaultExampleLoadingDescriptor) {
+ return CatalogDefaultExampleLoader(
+ descriptor: descriptor,
+ exampleState: exampleState,
+ );
+ }
+
+ if (descriptor is EmptyExampleLoadingDescriptor) {
+ return EmptyExampleLoader(
+ descriptor: descriptor,
+ exampleState: exampleState,
+ );
+ }
+
+ if (descriptor is StandardExampleLoadingDescriptor) {
+ return StandardExampleLoader(
+ descriptor: descriptor,
+ exampleState: exampleState,
+ );
+ }
+
+ if (descriptor is UserSharedExampleLoadingDescriptor) {
+ return UserSharedExampleLoader(
+ descriptor: descriptor,
+ exampleState: exampleState,
+ );
+ }
+
+ throw Exception('Unknown example loading descriptor: $descriptor');
+ }
+}
diff --git a/playground/frontend/lib/pages/playground/states/example_loaders/standard_example_loader.dart b/playground/frontend/lib/pages/playground/states/example_loaders/standard_example_loader.dart
new file mode 100644
index 00000000000..667f8f24e1d
--- /dev/null
+++ b/playground/frontend/lib/pages/playground/states/example_loaders/standard_example_loader.dart
@@ -0,0 +1,74 @@
+/*
+ * 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 'dart:async';
+
+import 'package:playground/modules/examples/models/example_loading_descriptors/standard_example_loading_descriptor.dart';
+import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground/modules/sdk/models/sdk.dart';
+import 'package:playground/pages/playground/states/example_loaders/example_loader.dart';
+import 'package:playground/pages/playground/states/examples_state.dart';
+
+/// Loads a given example from the local cache, then adds info from network.
+///
+/// This loader assumes that [ExampleState] is loading all examples to
+/// its cache. So it only completes if this is successful.
+class StandardExampleLoader extends ExampleLoader {
+ final StandardExampleLoadingDescriptor descriptor;
+ final ExampleState exampleState;
+ final _completer = Completer<ExampleModel>();
+
+ @override
+ Future<ExampleModel> get future => _completer.future;
+
+ StandardExampleLoader({
+ required this.descriptor,
+ required this.exampleState,
+ }) {
+ _load();
+ }
+
+ void _load() async {
+ final example = await _loadExampleWithoutInfo();
+
+ if (example == null) {
+ _completer.completeError('Example not found: $descriptor');
+ return;
+ }
+
+ _completer.complete(
+ exampleState.loadExampleInfo(example),
+ );
+ }
+
+ Future<ExampleModel?> _loadExampleWithoutInfo() {
+ return exampleState.hasExampleCatalog
+ ? exampleState.getCatalogExampleByPath(descriptor.path)
+ : _loadExampleFromRepository();
+ }
+
+ Future<ExampleModel?> _loadExampleFromRepository() async {
+ final sdk = SDK.tryParseExamplePath(descriptor.path);
+
+ if (sdk == null) {
+ return null;
+ }
+
+ return exampleState.getExample(descriptor.path, sdk);
+ }
+}
diff --git a/playground/frontend/lib/modules/examples/models/selector_size_model.dart b/playground/frontend/lib/pages/playground/states/example_loaders/user_shared_example_loader.dart
similarity index 53%
rename from playground/frontend/lib/modules/examples/models/selector_size_model.dart
rename to playground/frontend/lib/pages/playground/states/example_loaders/user_shared_example_loader.dart
index 27954f7ae22..0a658718a0b 100644
--- a/playground/frontend/lib/modules/examples/models/selector_size_model.dart
+++ b/playground/frontend/lib/pages/playground/states/example_loaders/user_shared_example_loader.dart
@@ -16,12 +16,21 @@
* limitations under the License.
*/
-class SelectorPositionModel {
- final double xAlignment;
- final double yAlignment;
+import 'package:playground/modules/examples/models/example_loading_descriptors/user_shared_example_loading_descriptor.dart';
+import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground/pages/playground/states/example_loaders/example_loader.dart';
+import 'package:playground/pages/playground/states/examples_state.dart';
- const SelectorPositionModel({
- required this.xAlignment,
- required this.yAlignment,
+class UserSharedExampleLoader extends ExampleLoader {
+ final UserSharedExampleLoadingDescriptor descriptor;
+ final ExampleState exampleState;
+
+ UserSharedExampleLoader({
+ required this.descriptor,
+ required this.exampleState,
});
+
+ @override
+ Future<ExampleModel> get future =>
+ exampleState.loadSharedExample(descriptor.snippetId);
}
diff --git a/playground/frontend/lib/pages/playground/states/example_selector_state.dart b/playground/frontend/lib/pages/playground/states/example_selector_state.dart
index 4e034535f36..fd9f8a1f907 100644
--- a/playground/frontend/lib/pages/playground/states/example_selector_state.dart
+++ b/playground/frontend/lib/pages/playground/states/example_selector_state.dart
@@ -21,17 +21,13 @@ import 'package:playground/modules/examples/models/category_model.dart';
import 'package:playground/modules/examples/models/example_model.dart';
import 'package:playground/pages/playground/states/playground_state.dart';
-import 'examples_state.dart';
-
class ExampleSelectorState with ChangeNotifier {
- final ExampleState _exampleState;
final PlaygroundState _playgroundState;
ExampleType _selectedFilterType;
String _filterText;
List<CategoryModel> categories;
ExampleSelectorState(
- this._exampleState,
this._playgroundState,
this.categories, [
this._selectedFilterType = ExampleType.all,
@@ -42,23 +38,26 @@ class ExampleSelectorState with ChangeNotifier {
String get filterText => _filterText;
- setSelectedFilterType(ExampleType type) {
+ void setSelectedFilterType(ExampleType type) {
_selectedFilterType = type;
notifyListeners();
}
- setFilterText(String text) {
+ void setFilterText(String text) {
_filterText = text;
notifyListeners();
}
- setCategories(List<CategoryModel>? categories) {
+ void setCategories(List<CategoryModel>? categories) {
this.categories = categories ?? [];
notifyListeners();
}
- sortCategories() {
- final categories = _exampleState.getCategories(_playgroundState.sdk)!;
+ void sortCategories() {
+ final categories = _playgroundState.exampleState.getCategories(
+ _playgroundState.sdk,
+ )!;
+
final sortedCategories = categories
.map((category) => CategoryModel(
name: category.name,
diff --git a/playground/frontend/lib/pages/playground/states/examples_state.dart b/playground/frontend/lib/pages/playground/states/examples_state.dart
index b080e361566..ff307dba928 100644
--- a/playground/frontend/lib/pages/playground/states/examples_state.dart
+++ b/playground/frontend/lib/pages/playground/states/examples_state.dart
@@ -16,13 +16,20 @@
* limitations under the License.
*/
+import 'dart:async';
+
+import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:playground/constants/params.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_repository.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/examples/repositories/models/shared_file_model.dart';
import 'package:playground/modules/sdk/models/sdk.dart';
class ExampleState with ChangeNotifier {
@@ -32,17 +39,26 @@ class ExampleState with ChangeNotifier {
ExampleModel? defaultExample;
bool isSelectorOpened = false;
+ final _allExamplesCompleter = Completer<void>();
+
+ Future<void> get allExamplesFuture => _allExamplesCompleter.future;
+
+ bool get hasExampleCatalog => !isEmbedded();
+
ExampleState(this._exampleRepository);
- init() {
- if (!Uri.base.toString().contains(kIsEmbedded)) {
- _loadCategories();
+ Future<void> init() async {
+ if (hasExampleCatalog) {
+ await Future.wait([
+ _loadCategories(),
+ loadDefaultExamplesIfNot(),
+ ]);
}
}
- setSdkCategories(Map<SDK, List<CategoryModel>> map) {
+ void setSdkCategories(Map<SDK, List<CategoryModel>> map) {
sdkCategories = map;
- notifyListeners();
+ _allExamplesCompleter.complete();
}
List<CategoryModel>? getCategories(SDK sdk) {
@@ -79,18 +95,46 @@ class ExampleState with ChangeNotifier {
);
}
- Future<ExampleModel> loadExampleInfo(ExampleModel example, SDK sdk) async {
+ Future<ExampleModel> loadSharedExample(String id) async {
+ GetSnippetResponse result = await _exampleRepository.getSnippet(
+ GetSnippetRequestWrapper(id: id),
+ );
+ return ExampleModel(
+ sdk: result.sdk,
+ name: result.files.first.name,
+ path: id,
+ description: '',
+ type: ExampleType.example,
+ source: result.files.first.code,
+ pipelineOptions: result.pipelineOptions,
+ );
+ }
+
+ Future<String> getSnippetId({
+ required List<SharedFile> files,
+ required SDK sdk,
+ required String pipelineOptions,
+ }) async {
+ String id = await _exampleRepository.saveSnippet(SaveSnippetRequestWrapper(
+ files: files,
+ sdk: sdk,
+ pipelineOptions: pipelineOptions,
+ ));
+ return id;
+ }
+
+ Future<ExampleModel> loadExampleInfo(ExampleModel example) async {
if (example.isInfoFetched()) {
return example;
}
//GRPC GetPrecompiledGraph errors hotfix
if (example.name == 'MinimalWordCount' &&
- (sdk == SDK.go || sdk == SDK.scio)) {
+ (example.sdk == SDK.go || example.sdk == SDK.scio)) {
final exampleData = await Future.wait([
- getExampleSource(example.path, sdk),
- getExampleOutput(example.path, sdk),
- getExampleLogs(example.path, sdk),
+ getExampleSource(example.path, example.sdk),
+ getExampleOutput(example.path, example.sdk),
+ getExampleLogs(example.path, example.sdk),
]);
example.setSource(exampleData[0]);
example.setOutputs(exampleData[1]);
@@ -99,10 +143,10 @@ class ExampleState with ChangeNotifier {
}
final exampleData = await Future.wait([
- getExampleSource(example.path, sdk),
- getExampleOutput(example.path, sdk),
- getExampleLogs(example.path, sdk),
- getExampleGraph(example.path, sdk)
+ getExampleSource(example.path, example.sdk),
+ getExampleOutput(example.path, example.sdk),
+ getExampleLogs(example.path, example.sdk),
+ getExampleGraph(example.path, example.sdk)
]);
example.setSource(exampleData[0]);
example.setOutputs(exampleData[1]);
@@ -111,15 +155,15 @@ class ExampleState with ChangeNotifier {
return example;
}
- _loadCategories() {
- _exampleRepository
+ Future<void> _loadCategories() {
+ return _exampleRepository
.getListOfExamples(
GetListOfExamplesRequestWrapper(sdk: null, category: null),
)
.then((map) => setSdkCategories(map));
}
- changeSelectorVisibility() {
+ void changeSelectorVisibility() {
isSelectorOpened = !isSelectorOpened;
notifyListeners();
}
@@ -147,7 +191,7 @@ class ExampleState with ChangeNotifier {
final futures = <Future<void>>[];
for (var entry in defaultExamplesMap.entries) {
- final exampleFuture = loadExampleInfo(entry.value, entry.key)
+ final exampleFuture = loadExampleInfo(entry.value)
.then((value) => defaultExamplesMap[entry.key] = value);
futures.add(exampleFuture);
}
@@ -163,4 +207,16 @@ class ExampleState with ChangeNotifier {
await loadDefaultExamples();
}
+
+ Future<ExampleModel?> getCatalogExampleByPath(String path) async {
+ await allExamplesFuture;
+
+ final allExamples = sdkCategories?.values
+ .expand((sdkCategory) => sdkCategory.map((e) => e.examples))
+ .expand((element) => element);
+
+ return allExamples?.firstWhereOrNull(
+ (e) => e.path == path,
+ );
+ }
}
diff --git a/playground/frontend/lib/pages/playground/states/playground_state.dart b/playground/frontend/lib/pages/playground/states/playground_state.dart
index 2340de7b8f8..c0173e47153 100644
--- a/playground/frontend/lib/pages/playground/states/playground_state.dart
+++ b/playground/frontend/lib/pages/playground/states/playground_state.dart
@@ -25,9 +25,12 @@ import 'package:playground/modules/editor/parsers/run_options_parser.dart';
import 'package:playground/modules/editor/repository/code_repository/code_repository.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/examples/models/example_loading_descriptors/examples_loading_descriptor_factory.dart';
import 'package:playground/modules/examples/models/example_model.dart';
import 'package:playground/modules/examples/models/outputs_model.dart';
import 'package:playground/modules/sdk/models/sdk.dart';
+import 'package:playground/pages/playground/states/example_loaders/examples_loader.dart';
+import 'package:playground/pages/playground/states/examples_state.dart';
const kTitleLength = 15;
const kExecutionTimeUpdate = 100;
@@ -40,6 +43,9 @@ const kCachedResultsLog =
'The results of this example are taken from the Apache Beam Playground cache.\n';
class PlaygroundState with ChangeNotifier {
+ final ExampleState exampleState;
+ final ExamplesLoader examplesLoader;
+
final CodeController codeController;
SDK _sdk;
CodeRepository? _codeRepository;
@@ -52,17 +58,24 @@ class PlaygroundState with ChangeNotifier {
String? outputResult;
PlaygroundState({
+ required this.exampleState,
+ required this.examplesLoader,
SDK sdk = SDK.java,
- ExampleModel? selectedExample,
CodeRepository? codeRepository,
}) : _sdk = sdk,
codeController = CodeController(
language: sdk.highlightMode,
webSpaceFix: false,
) {
- _selectedExample = selectedExample;
- _pipelineOptions = selectedExample?.pipelineOptions ?? '';
- codeController.text = _selectedExample?.source ?? '';
+ final uri = Uri.base;
+ final descriptor = ExamplesLoadingDescriptorFactory.fromUriParts(
+ path: uri.path,
+ params: uri.queryParameters,
+ );
+
+ examplesLoader.setPlaygroundState(this);
+ examplesLoader.load(descriptor);
+
_codeRepository = codeRepository;
selectedOutputFilterType = OutputType.all;
outputResult = '';
@@ -101,6 +114,7 @@ class PlaygroundState with ChangeNotifier {
void setExample(ExampleModel example) {
_selectedExample = example;
+ setSdk(example.sdk, notify: false);
_pipelineOptions = example.pipelineOptions ?? '';
codeController.text = example.source ?? '';
_result = null;
@@ -109,13 +123,16 @@ class PlaygroundState with ChangeNotifier {
notifyListeners();
}
- void setSdk(SDK sdk) {
+ void setSdk(SDK sdk, {bool notify = true}) {
_sdk = sdk;
codeController.language = sdk.highlightMode;
- notifyListeners();
+
+ if (notify) {
+ notifyListeners();
+ }
}
- void setSource(String source) {
+ set source(String source) {
codeController.text = source;
}
@@ -138,7 +155,7 @@ class PlaygroundState with ChangeNotifier {
codeController.text = _selectedExample?.source ?? '';
_pipelineOptions = selectedExample?.pipelineOptions ?? '';
_executionTime = null;
- setOutputResult('');
+ outputResult = '';
notifyListeners();
}
diff --git a/playground/frontend/lib/playground_app.dart b/playground/frontend/lib/playground_app.dart
index 4fbde3ff576..8c5f2a489e6 100644
--- a/playground/frontend/lib/playground_app.dart
+++ b/playground/frontend/lib/playground_app.dart
@@ -23,7 +23,6 @@ import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:playground/config/locale.dart';
import 'package:playground/config/theme.dart';
import 'package:playground/l10n/l10n.dart';
-import 'package:playground/modules/editor/components/editor_themes.dart';
import 'package:playground/pages/playground/components/playground_page_providers.dart';
import 'package:playground/pages/playground/playground_page.dart';
import 'package:playground/pages/routes.dart';
@@ -34,38 +33,38 @@ class PlaygroundApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return ChangeNotifierProvider(
- create: (context) => ThemeProvider()..init(),
- builder: (context, _) {
- final themeProvider = Provider.of<ThemeProvider>(context);
- return CodeTheme(
- data: themeProvider.isDarkMode ? kDarkCodeTheme : kLightCodeTheme,
- child: ChangeNotifierProvider<LocaleProvider>(
- create: (context) => LocaleProvider(),
- builder: (context, state) {
- final localeProvider = Provider.of<LocaleProvider>(context);
- return PlaygroundPageProviders(
- child: MaterialApp(
- title: 'Apache Beam Playground',
- themeMode: themeProvider.themeMode,
- theme: kLightTheme,
- darkTheme: kDarkTheme,
- onGenerateRoute: Routes.generateRoute,
- home: const PlaygroundPage(),
- debugShowCheckedModeBanner: false,
- locale: localeProvider.locale,
- supportedLocales: L10n.locales,
- localizationsDelegates: const [
- AppLocalizations.delegate,
- GlobalMaterialLocalizations.delegate,
- GlobalWidgetsLocalizations.delegate,
- ],
- ),
- );
- },
- ),
- );
- },
+ return ThemeSwitchNotifierProvider(
+ child: Consumer<ThemeSwitchNotifier>(
+ builder: (context, themeSwitchNotifier, _) {
+ return CodeTheme(
+ data: themeSwitchNotifier.codeTheme,
+ child: ChangeNotifierProvider<LocaleProvider>(
+ create: (context) => LocaleProvider(),
+ builder: (context, state) {
+ final localeProvider = Provider.of<LocaleProvider>(context);
+ return PlaygroundPageProviders(
+ child: MaterialApp(
+ title: 'Apache Beam Playground',
+ themeMode: themeSwitchNotifier.themeMode,
+ theme: kLightTheme,
+ darkTheme: kDarkTheme,
+ onGenerateRoute: Routes.generateRoute,
+ home: const PlaygroundPage(),
+ debugShowCheckedModeBanner: false,
+ locale: localeProvider.locale,
+ supportedLocales: L10n.locales,
+ localizationsDelegates: const [
+ AppLocalizations.delegate,
+ GlobalMaterialLocalizations.delegate,
+ GlobalWidgetsLocalizations.delegate,
+ ],
+ ),
+ );
+ },
+ ),
+ );
+ },
+ ),
);
}
}
diff --git a/playground/frontend/lib/utils/dropdown_utils.dart b/playground/frontend/lib/utils/dropdown_utils.dart
new file mode 100644
index 00000000000..6ebb251a3df
--- /dev/null
+++ b/playground/frontend/lib/utils/dropdown_utils.dart
@@ -0,0 +1,48 @@
+/*
+ * 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/dropdown_button/dropdown_button.dart';
+
+const _bottomToDropdown = 10.0;
+
+/// Returns the screen offset at which to show the dropdown.
+///
+/// [key] points to the button that triggers the dropdown.
+/// [widgetWidth] is important when aligning to the right.
+Offset findDropdownOffset({
+ required GlobalKey key,
+ DropdownAlignment alignment = DropdownAlignment.left,
+ double widgetWidth = 0,
+}) {
+ final box = key.currentContext?.findRenderObject() as RenderBox?;
+
+ if (box == null) {
+ throw Exception('Cannot find render object for $key');
+ }
+
+ final buttonOffset = box.localToGlobal(Offset.zero);
+ final top = buttonOffset.dy + box.size.height + _bottomToDropdown;
+
+ switch (alignment) {
+ case DropdownAlignment.left:
+ return Offset(buttonOffset.dx, top);
+ case DropdownAlignment.right:
+ return Offset(buttonOffset.dx + box.size.width - widgetWidth, top);
+ }
+}
diff --git a/playground/frontend/lib/utils/share_code_utils.dart b/playground/frontend/lib/utils/share_code_utils.dart
new file mode 100644
index 00000000000..03aac0821b3
--- /dev/null
+++ b/playground/frontend/lib/utils/share_code_utils.dart
@@ -0,0 +1,111 @@
+/*
+ * 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 'dart:convert';
+
+import 'package:playground/constants/params.dart';
+
+enum PlaygroundView {
+ standalone,
+ embedded,
+ ;
+
+ String get path {
+ switch (this) {
+ case PlaygroundView.standalone:
+ return '/';
+ case PlaygroundView.embedded:
+ return '/embedded';
+ }
+ }
+}
+
+extension CopyWith on Uri {
+ Uri copyWith({
+ String? path,
+ Map<String, dynamic>? queryParameters,
+ }) {
+ return Uri(
+ scheme: scheme,
+ userInfo: userInfo,
+ host: host,
+ port: port,
+ path: path ?? this.path,
+ queryParameters: queryParameters ?? this.queryParameters,
+ );
+ }
+}
+
+class ShareCodeUtils {
+ static const _width = '90%';
+ static const _height = '600px';
+
+ static Uri examplePathToPlaygroundUrl({
+ required String examplePath,
+ required PlaygroundView view,
+ }) {
+ return Uri.base.copyWith(
+ path: view.path,
+ queryParameters: _getExampleQueryParameters(
+ examplePath: examplePath,
+ view: view,
+ ),
+ );
+ }
+
+ static Map<String, dynamic> _getExampleQueryParameters({
+ required String examplePath,
+ required PlaygroundView view,
+ }) {
+ switch (view) {
+ case PlaygroundView.standalone:
+ return {
+ kExampleParam: examplePath,
+ };
+ case PlaygroundView.embedded:
+ return {
+ kIsEditableParam: '1',
+ kExampleParam: examplePath,
+ };
+ }
+ }
+
+ static String examplePathToIframeCode({
+ required String examplePath,
+ }) {
+ return _iframe(
+ src: examplePathToPlaygroundUrl(
+ examplePath: examplePath,
+ view: PlaygroundView.embedded,
+ ),
+ );
+ }
+
+ static String _iframe({
+ required Uri src,
+ }) {
+ return '<iframe'
+ ' src="${Uri.encodeComponent(src.toString())}"'
+ ' width="${_htmlEscape(_width)}"'
+ ' height="${_htmlEscape(_height)}"'
+ ' allow="clipboard-write" '
+ '></iframe>';
+ }
+
+ static String _htmlEscape(String text) => const HtmlEscape().convert(text);
+}
diff --git a/playground/frontend/test/modules/editor/repository/example_repository/example_repository_test.mocks.dart b/playground/frontend/test/modules/editor/repository/example_repository/example_repository_test.mocks.dart
index 61dd8b27670..92bcb2546a5 100644
--- a/playground/frontend/test/modules/editor/repository/example_repository/example_repository_test.mocks.dart
+++ b/playground/frontend/test/modules/editor/repository/example_repository/example_repository_test.mocks.dart
@@ -20,23 +20,31 @@
// in playground/test/modules/editor/repository/example_repository/example_repository_test.dart.
// Do not manually edit this file.
-import 'dart:async' as _i7;
+import 'dart:async' as _i9;
import 'package:mockito/mockito.dart' as _i1;
import 'package:playground/modules/editor/repository/code_repository/code_client/output_response.dart'
as _i5;
import 'package:playground/modules/examples/repositories/example_client/example_client.dart'
- as _i6;
+ as _i8;
import 'package:playground/modules/examples/repositories/models/get_example_code_response.dart'
as _i3;
import 'package:playground/modules/examples/repositories/models/get_example_request.dart'
- as _i9;
+ as _i11;
import 'package:playground/modules/examples/repositories/models/get_example_response.dart'
as _i4;
import 'package:playground/modules/examples/repositories/models/get_list_of_examples_request.dart'
- as _i8;
+ as _i10;
import 'package:playground/modules/examples/repositories/models/get_list_of_examples_response.dart'
as _i2;
+import 'package:playground/modules/examples/repositories/models/get_snippet_request.dart'
+ as _i12;
+import 'package:playground/modules/examples/repositories/models/get_snippet_response.dart'
+ as _i6;
+import 'package:playground/modules/examples/repositories/models/save_snippet_request.dart'
+ as _i13;
+import 'package:playground/modules/examples/repositories/models/save_snippet_response.dart'
+ as _i7;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
@@ -59,61 +67,81 @@ class _FakeGetExampleResponse_2 extends _i1.Fake
class _FakeOutputResponse_3 extends _i1.Fake implements _i5.OutputResponse {}
+class _FakeGetSnippetResponse_4 extends _i1.Fake
+ implements _i6.GetSnippetResponse {}
+
+class _FakeSaveSnippetResponse_5 extends _i1.Fake
+ implements _i7.SaveSnippetResponse {}
+
/// A class which mocks [ExampleClient].
///
/// See the documentation for Mockito's code generation for more information.
-class MockExampleClient extends _i1.Mock implements _i6.ExampleClient {
+class MockExampleClient extends _i1.Mock implements _i8.ExampleClient {
MockExampleClient() {
_i1.throwOnMissingStub(this);
}
@override
- _i7.Future<_i2.GetListOfExampleResponse> getListOfExamples(
- _i8.GetListOfExamplesRequestWrapper? request) =>
+ _i9.Future<_i2.GetListOfExampleResponse> getListOfExamples(
+ _i10.GetListOfExamplesRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getListOfExamples, [request]),
returnValue: Future<_i2.GetListOfExampleResponse>.value(
_FakeGetListOfExampleResponse_0()))
- as _i7.Future<_i2.GetListOfExampleResponse>);
+ as _i9.Future<_i2.GetListOfExampleResponse>);
@override
- _i7.Future<_i3.GetExampleCodeResponse> getExampleSource(
- _i9.GetExampleRequestWrapper? request) =>
+ _i9.Future<_i3.GetExampleCodeResponse> getExampleSource(
+ _i11.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getExampleSource, [request]),
returnValue: Future<_i3.GetExampleCodeResponse>.value(
_FakeGetExampleCodeResponse_1()))
- as _i7.Future<_i3.GetExampleCodeResponse>);
+ as _i9.Future<_i3.GetExampleCodeResponse>);
@override
- _i7.Future<_i4.GetExampleResponse> getDefaultExample(
- _i9.GetExampleRequestWrapper? request) =>
+ _i9.Future<_i4.GetExampleResponse> getDefaultExample(
+ _i11.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getDefaultExample, [request]),
returnValue: Future<_i4.GetExampleResponse>.value(
_FakeGetExampleResponse_2()))
- as _i7.Future<_i4.GetExampleResponse>);
+ as _i9.Future<_i4.GetExampleResponse>);
@override
- _i7.Future<_i4.GetExampleResponse> getExample(
- _i9.GetExampleRequestWrapper? request) =>
+ _i9.Future<_i4.GetExampleResponse> getExample(
+ _i11.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getExample, [request]),
returnValue: Future<_i4.GetExampleResponse>.value(
_FakeGetExampleResponse_2()))
- as _i7.Future<_i4.GetExampleResponse>);
+ as _i9.Future<_i4.GetExampleResponse>);
@override
- _i7.Future<_i5.OutputResponse> getExampleOutput(
- _i9.GetExampleRequestWrapper? request) =>
+ _i9.Future<_i5.OutputResponse> getExampleOutput(
+ _i11.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getExampleOutput, [request]),
returnValue:
Future<_i5.OutputResponse>.value(_FakeOutputResponse_3()))
- as _i7.Future<_i5.OutputResponse>);
+ as _i9.Future<_i5.OutputResponse>);
@override
- _i7.Future<_i5.OutputResponse> getExampleLogs(
- _i9.GetExampleRequestWrapper? request) =>
+ _i9.Future<_i5.OutputResponse> getExampleLogs(
+ _i11.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getExampleLogs, [request]),
returnValue:
Future<_i5.OutputResponse>.value(_FakeOutputResponse_3()))
- as _i7.Future<_i5.OutputResponse>);
+ as _i9.Future<_i5.OutputResponse>);
@override
- _i7.Future<_i5.OutputResponse> getExampleGraph(
- _i9.GetExampleRequestWrapper? request) =>
+ _i9.Future<_i5.OutputResponse> getExampleGraph(
+ _i11.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getExampleGraph, [request]),
returnValue:
Future<_i5.OutputResponse>.value(_FakeOutputResponse_3()))
- as _i7.Future<_i5.OutputResponse>);
+ as _i9.Future<_i5.OutputResponse>);
+ @override
+ _i9.Future<_i6.GetSnippetResponse> getSnippet(
+ _i12.GetSnippetRequestWrapper? request) =>
+ (super.noSuchMethod(Invocation.method(#getSnippet, [request]),
+ returnValue: Future<_i6.GetSnippetResponse>.value(
+ _FakeGetSnippetResponse_4()))
+ as _i9.Future<_i6.GetSnippetResponse>);
+ @override
+ _i9.Future<_i7.SaveSnippetResponse> saveSnippet(
+ _i13.SaveSnippetRequestWrapper? request) =>
+ (super.noSuchMethod(Invocation.method(#saveSnippet, [request]),
+ returnValue: Future<_i7.SaveSnippetResponse>.value(
+ _FakeSaveSnippetResponse_5()))
+ as _i9.Future<_i7.SaveSnippetResponse>);
}
diff --git a/playground/frontend/test/pages/playground/states/example_selector_state_test.dart b/playground/frontend/test/pages/playground/states/example_selector_state_test.dart
index 0198397a795..99d847f38e0 100644
--- a/playground/frontend/test/pages/playground/states/example_selector_state_test.dart
+++ b/playground/frontend/test/pages/playground/states/example_selector_state_test.dart
@@ -19,27 +19,29 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.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/example_repository.dart';
+import 'package:playground/pages/playground/states/example_loaders/examples_loader.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 'example_selector_state_test.mocks.dart';
import 'mocks/categories_mock.dart';
+import 'mocks/example_repository_mock.dart';
-@GenerateMocks([ExampleClient])
+@GenerateMocks([ExamplesLoader])
void main() {
late PlaygroundState playgroundState;
late ExampleState exampleState;
late ExampleSelectorState state;
- late ExampleClient client;
+ final mockExampleRepository = getMockExampleRepository();
setUp(() {
- client = MockExampleClient();
- playgroundState = PlaygroundState();
- exampleState = ExampleState(ExampleRepository(client));
- state = ExampleSelectorState(exampleState, playgroundState, []);
+ exampleState = ExampleState(mockExampleRepository);
+ playgroundState = PlaygroundState(
+ examplesLoader: MockExamplesLoader(),
+ exampleState: exampleState,
+ );
+ state = ExampleSelectorState(playgroundState, []);
});
test(
@@ -105,7 +107,6 @@ void main() {
'but should NOT:'
'- affect Example state categories', () {
final state = ExampleSelectorState(
- exampleState,
playgroundState,
categoriesMock,
);
@@ -125,7 +126,6 @@ void main() {
'- be sensitive for register,'
'- affect Example state categories', () {
final state = ExampleSelectorState(
- exampleState,
playgroundState,
categoriesMock,
);
diff --git a/playground/frontend/test/pages/playground/states/example_selector_state_test.mocks.dart b/playground/frontend/test/pages/playground/states/example_selector_state_test.mocks.dart
index a9009516d30..12d12962c5a 100644
--- a/playground/frontend/test/pages/playground/states/example_selector_state_test.mocks.dart
+++ b/playground/frontend/test/pages/playground/states/example_selector_state_test.mocks.dart
@@ -19,23 +19,15 @@
// in playground/test/pages/playground/states/example_selector_state_test.dart.
// Do not manually edit this file.
-import 'dart:async' as _i7;
+import 'dart:async' as _i4;
import 'package:mockito/mockito.dart' as _i1;
-import 'package:playground/modules/editor/repository/code_repository/code_client/output_response.dart'
+import 'package:playground/modules/examples/models/example_loading_descriptors/examples_loading_descriptor.dart'
as _i5;
-import 'package:playground/modules/examples/repositories/example_client/example_client.dart'
- as _i6;
-import 'package:playground/modules/examples/repositories/models/get_example_code_response.dart'
- as _i3;
-import 'package:playground/modules/examples/repositories/models/get_example_request.dart'
- as _i9;
-import 'package:playground/modules/examples/repositories/models/get_example_response.dart'
- as _i4;
-import 'package:playground/modules/examples/repositories/models/get_list_of_examples_request.dart'
- as _i8;
-import 'package:playground/modules/examples/repositories/models/get_list_of_examples_response.dart'
+import 'package:playground/pages/playground/states/example_loaders/examples_loader.dart'
as _i2;
+import 'package:playground/pages/playground/states/playground_state.dart'
+ as _i3;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
@@ -47,72 +39,21 @@ import 'package:playground/modules/examples/repositories/models/get_list_of_exam
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
-class _FakeGetListOfExampleResponse_0 extends _i1.Fake
- implements _i2.GetListOfExampleResponse {}
-
-class _FakeGetExampleCodeResponse_1 extends _i1.Fake
- implements _i3.GetExampleCodeResponse {}
-
-class _FakeGetExampleResponse_2 extends _i1.Fake
- implements _i4.GetExampleResponse {}
-
-class _FakeOutputResponse_3 extends _i1.Fake implements _i5.OutputResponse {}
-
-/// A class which mocks [ExampleClient].
+/// A class which mocks [ExamplesLoader].
///
/// See the documentation for Mockito's code generation for more information.
-class MockExampleClient extends _i1.Mock implements _i6.ExampleClient {
- MockExampleClient() {
+class MockExamplesLoader extends _i1.Mock implements _i2.ExamplesLoader {
+ MockExamplesLoader() {
_i1.throwOnMissingStub(this);
}
@override
- _i7.Future<_i2.GetListOfExampleResponse> getListOfExamples(
- _i8.GetListOfExamplesRequestWrapper? request) =>
- (super.noSuchMethod(Invocation.method(#getListOfExamples, [request]),
- returnValue: Future<_i2.GetListOfExampleResponse>.value(
- _FakeGetListOfExampleResponse_0()))
- as _i7.Future<_i2.GetListOfExampleResponse>);
- @override
- _i7.Future<_i3.GetExampleCodeResponse> getExampleSource(
- _i9.GetExampleRequestWrapper? request) =>
- (super.noSuchMethod(Invocation.method(#getExampleSource, [request]),
- returnValue: Future<_i3.GetExampleCodeResponse>.value(
- _FakeGetExampleCodeResponse_1()))
- as _i7.Future<_i3.GetExampleCodeResponse>);
- @override
- _i7.Future<_i4.GetExampleResponse> getDefaultExample(
- _i9.GetExampleRequestWrapper? request) =>
- (super.noSuchMethod(Invocation.method(#getDefaultExample, [request]),
- returnValue: Future<_i4.GetExampleResponse>.value(
- _FakeGetExampleResponse_2()))
- as _i7.Future<_i4.GetExampleResponse>);
- @override
- _i7.Future<_i4.GetExampleResponse> getExample(
- _i9.GetExampleRequestWrapper? request) =>
- (super.noSuchMethod(Invocation.method(#getExample, [request]),
- returnValue: Future<_i4.GetExampleResponse>.value(
- _FakeGetExampleResponse_2()))
- as _i7.Future<_i4.GetExampleResponse>);
- @override
- _i7.Future<_i5.OutputResponse> getExampleOutput(
- _i9.GetExampleRequestWrapper? request) =>
- (super.noSuchMethod(Invocation.method(#getExampleOutput, [request]),
- returnValue:
- Future<_i5.OutputResponse>.value(_FakeOutputResponse_3()))
- as _i7.Future<_i5.OutputResponse>);
- @override
- _i7.Future<_i5.OutputResponse> getExampleLogs(
- _i9.GetExampleRequestWrapper? request) =>
- (super.noSuchMethod(Invocation.method(#getExampleLogs, [request]),
- returnValue:
- Future<_i5.OutputResponse>.value(_FakeOutputResponse_3()))
- as _i7.Future<_i5.OutputResponse>);
+ void setPlaygroundState(_i3.PlaygroundState? value) =>
+ super.noSuchMethod(Invocation.method(#setPlaygroundState, [value]),
+ returnValueForMissingStub: null);
@override
- _i7.Future<_i5.OutputResponse> getExampleGraph(
- _i9.GetExampleRequestWrapper? request) =>
- (super.noSuchMethod(Invocation.method(#getExampleGraph, [request]),
- returnValue:
- Future<_i5.OutputResponse>.value(_FakeOutputResponse_3()))
- as _i7.Future<_i5.OutputResponse>);
+ _i4.Future<void> load(_i5.ExamplesLoadingDescriptor? descriptor) =>
+ (super.noSuchMethod(Invocation.method(#load, [descriptor]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
}
diff --git a/playground/frontend/test/pages/playground/states/examples_state_test.dart b/playground/frontend/test/pages/playground/states/examples_state_test.dart
index 5416ff7be82..169dce298a2 100644
--- a/playground/frontend/test/pages/playground/states/examples_state_test.dart
+++ b/playground/frontend/test/pages/playground/states/examples_state_test.dart
@@ -17,15 +17,14 @@
*/
import 'package:flutter_test/flutter_test.dart';
-import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
-import 'package:playground/modules/examples/repositories/example_repository.dart';
import 'package:playground/modules/sdk/models/sdk.dart';
import 'package:playground/pages/playground/states/examples_state.dart';
-import 'examples_state_test.mocks.dart';
import 'mocks/categories_mock.dart';
import 'mocks/example_mock.dart';
+import 'mocks/example_repository_mock.dart';
+import 'mocks/example_repository_mock.mocks.dart';
import 'mocks/request_mock.dart';
final kDefaultExamplesMapMock = {
@@ -35,13 +34,12 @@ final kDefaultExamplesMapMock = {
SDK.scio: exampleWithAllAdditionsMock,
};
-@GenerateMocks([ExampleRepository])
void main() {
late ExampleState state;
late MockExampleRepository mockRepo;
setUp(() {
- mockRepo = MockExampleRepository();
+ mockRepo = getMockExampleRepository();
state = ExampleState(mockRepo);
});
@@ -148,7 +146,7 @@ void main() {
'then loadExampleInfo should return example immediately',
() async {
expect(
- await state.loadExampleInfo(exampleMock1, SDK.java),
+ await state.loadExampleInfo(exampleMock1),
exampleMock1,
);
},
@@ -157,19 +155,8 @@ void main() {
test(
'Example state loadExampleInfo should load source, output, logs, graph for given example',
() async {
- // stubs
- when(mockRepo.getExampleOutput(kRequestForExampleInfo))
- .thenAnswer((_) async => kOutputResponseMock.output);
- when(mockRepo.getExampleSource(kRequestForExampleInfo))
- .thenAnswer((_) async => kOutputResponseMock.output);
- when(mockRepo.getExampleLogs(kRequestForExampleInfo))
- .thenAnswer((_) async => kOutputResponseMock.output);
- when(mockRepo.getExampleGraph(kRequestForExampleInfo))
- .thenAnswer((_) async => kOutputResponseMock.output);
-
- // test assertion
expect(
- await state.loadExampleInfo(exampleWithoutSourceMock, SDK.java),
+ await state.loadExampleInfo(exampleWithoutSourceMock),
exampleWithAllAdditionsMock,
);
},
@@ -190,14 +177,6 @@ void main() {
'with all additions for every Sdk',
() async {
// stubs
- when(mockRepo.getDefaultExample(kRequestDefaultExampleForJava))
- .thenAnswer((_) async => exampleWithoutSourceMock);
- when(mockRepo.getDefaultExample(kRequestDefaultExampleForGo))
- .thenAnswer((_) async => exampleWithoutSourceMock);
- when(mockRepo.getDefaultExample(kRequestDefaultExampleForPython))
- .thenAnswer((_) async => exampleWithoutSourceMock);
- when(mockRepo.getDefaultExample(kRequestDefaultExampleForScio))
- .thenAnswer((_) async => exampleWithoutSourceMock);
when(mockRepo.getExampleOutput(kRequestForExampleInfo))
.thenAnswer((_) async => kOutputResponseMock.output);
when(mockRepo.getExampleSource(kRequestForExampleInfo))
diff --git a/playground/frontend/test/pages/playground/states/mocks/example_mock.dart b/playground/frontend/test/pages/playground/states/mocks/example_mock.dart
index 0be09e915f0..f0833e8afb4 100644
--- a/playground/frontend/test/pages/playground/states/mocks/example_mock.dart
+++ b/playground/frontend/test/pages/playground/states/mocks/example_mock.dart
@@ -17,37 +17,51 @@
*/
import 'package:playground/modules/examples/models/example_model.dart';
+import 'package:playground/modules/sdk/models/sdk.dart';
final ExampleModel exampleMock1 = ExampleModel(
+ sdk: SDK.python,
source: 'ex1',
name: 'Example',
type: ExampleType.example,
description: 'description',
- path: 'SDK/Category/Name',
+ path: 'SDK_PYTHON/Category/Name',
);
final ExampleModel exampleMock2 = ExampleModel(
+ sdk: SDK.python,
source: 'ex2',
name: 'Kata',
type: ExampleType.kata,
description: 'description',
- path: 'SDK/Category/Name',
+ path: 'SDK_PYTHON/Category/Name',
);
final ExampleModel exampleWithoutSourceMock = ExampleModel(
+ sdk: SDK.python,
name: 'Test example',
type: ExampleType.example,
description: 'description',
- path: 'SDK/Category/Name',
+ path: 'SDK_PYTHON/Category/Name',
);
final ExampleModel exampleWithAllAdditionsMock = ExampleModel(
+ sdk: SDK.python,
name: 'Test example',
type: ExampleType.example,
description: 'description',
- path: 'SDK/Category/Name',
+ path: 'SDK_PYTHON/Category/Name',
source: 'test outputs',
outputs: 'test outputs',
logs: 'test outputs',
graph: 'test outputs',
);
+
+final ExampleModel exampleMockGo = ExampleModel(
+ sdk: SDK.go,
+ source: 'ex1',
+ name: 'Example',
+ type: ExampleType.example,
+ description: 'description',
+ path: 'SDK_GO/Category/Name',
+);
diff --git a/playground/frontend/test/pages/playground/states/mocks/example_repository_mock.dart b/playground/frontend/test/pages/playground/states/mocks/example_repository_mock.dart
new file mode 100644
index 00000000000..e44c5f03b4e
--- /dev/null
+++ b/playground/frontend/test/pages/playground/states/mocks/example_repository_mock.dart
@@ -0,0 +1,51 @@
+/*
+ * 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:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+import 'package:playground/modules/examples/repositories/example_repository.dart';
+
+import 'example_repository_mock.mocks.dart';
+import 'example_mock.dart';
+import 'request_mock.dart';
+
+@GenerateMocks([ExampleRepository])
+MockExampleRepository getMockExampleRepository() {
+ final m = MockExampleRepository();
+
+ // stubs
+ when(m.getDefaultExample(kRequestDefaultExampleForJava))
+ .thenAnswer((_) async => exampleWithoutSourceMock);
+ when(m.getDefaultExample(kRequestDefaultExampleForGo))
+ .thenAnswer((_) async => exampleWithoutSourceMock);
+ when(m.getDefaultExample(kRequestDefaultExampleForPython))
+ .thenAnswer((_) async => exampleWithoutSourceMock);
+ when(m.getDefaultExample(kRequestDefaultExampleForScio))
+ .thenAnswer((_) async => exampleWithoutSourceMock);
+
+ when(m.getExampleOutput(kRequestForExampleInfo))
+ .thenAnswer((_) async => kOutputResponseMock.output);
+ when(m.getExampleSource(kRequestForExampleInfo))
+ .thenAnswer((_) async => kOutputResponseMock.output);
+ when(m.getExampleLogs(kRequestForExampleInfo))
+ .thenAnswer((_) async => kOutputResponseMock.output);
+ when(m.getExampleGraph(kRequestForExampleInfo))
+ .thenAnswer((_) async => kOutputResponseMock.output);
+
+ return m;
+}
diff --git a/playground/frontend/test/pages/playground/states/examples_state_test.mocks.dart b/playground/frontend/test/pages/playground/states/mocks/example_repository_mock.mocks.dart
similarity index 55%
rename from playground/frontend/test/pages/playground/states/examples_state_test.mocks.dart
rename to playground/frontend/test/pages/playground/states/mocks/example_repository_mock.mocks.dart
index 832064e2527..8215315d7fc 100644
--- a/playground/frontend/test/pages/playground/states/examples_state_test.mocks.dart
+++ b/playground/frontend/test/pages/playground/states/mocks/example_repository_mock.mocks.dart
@@ -16,22 +16,28 @@
* limitations under the License.
*/
-// Mocks generated by Mockito 5.0.16 from annotations
-// in playground/test/pages/playground/states/examples_state_test.dart.
+// Mocks generated by Mockito 5.2.0 from annotations
+// in playground/test/pages/playground/states/mocks/example_repository_mock.dart.
// Do not manually edit this file.
-import 'dart:async' as _i4;
+import 'dart:async' as _i5;
import 'package:mockito/mockito.dart' as _i1;
-import 'package:playground/modules/examples/models/category_model.dart' as _i6;
+import 'package:playground/modules/examples/models/category_model.dart' as _i7;
import 'package:playground/modules/examples/models/example_model.dart' as _i2;
import 'package:playground/modules/examples/repositories/example_repository.dart'
- as _i3;
+ as _i4;
import 'package:playground/modules/examples/repositories/models/get_example_request.dart'
- as _i8;
+ as _i9;
import 'package:playground/modules/examples/repositories/models/get_list_of_examples_request.dart'
- as _i7;
-import 'package:playground/modules/sdk/models/sdk.dart' as _i5;
+ as _i8;
+import 'package:playground/modules/examples/repositories/models/get_snippet_request.dart'
+ as _i10;
+import 'package:playground/modules/examples/repositories/models/get_snippet_response.dart'
+ as _i3;
+import 'package:playground/modules/examples/repositories/models/save_snippet_request.dart'
+ as _i11;
+import 'package:playground/modules/sdk/models/sdk.dart' as _i6;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
@@ -45,49 +51,63 @@ import 'package:playground/modules/sdk/models/sdk.dart' as _i5;
class _FakeExampleModel_0 extends _i1.Fake implements _i2.ExampleModel {}
+class _FakeGetSnippetResponse_1 extends _i1.Fake
+ implements _i3.GetSnippetResponse {}
+
/// A class which mocks [ExampleRepository].
///
/// See the documentation for Mockito's code generation for more information.
-class MockExampleRepository extends _i1.Mock implements _i3.ExampleRepository {
+class MockExampleRepository extends _i1.Mock implements _i4.ExampleRepository {
MockExampleRepository() {
_i1.throwOnMissingStub(this);
}
@override
- _i4.Future<Map<_i5.SDK, List<_i6.CategoryModel>>> getListOfExamples(
- _i7.GetListOfExamplesRequestWrapper? request) =>
+ _i5.Future<Map<_i6.SDK, List<_i7.CategoryModel>>> getListOfExamples(
+ _i8.GetListOfExamplesRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getListOfExamples, [request]),
- returnValue: Future<Map<_i5.SDK, List<_i6.CategoryModel>>>.value(
- <_i5.SDK, List<_i6.CategoryModel>>{}))
- as _i4.Future<Map<_i5.SDK, List<_i6.CategoryModel>>>);
+ returnValue: Future<Map<_i6.SDK, List<_i7.CategoryModel>>>.value(
+ <_i6.SDK, List<_i7.CategoryModel>>{}))
+ as _i5.Future<Map<_i6.SDK, List<_i7.CategoryModel>>>);
@override
- _i4.Future<_i2.ExampleModel> getDefaultExample(
- _i8.GetExampleRequestWrapper? request) =>
+ _i5.Future<_i2.ExampleModel> getDefaultExample(
+ _i9.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getDefaultExample, [request]),
returnValue:
Future<_i2.ExampleModel>.value(_FakeExampleModel_0()))
- as _i4.Future<_i2.ExampleModel>);
+ as _i5.Future<_i2.ExampleModel>);
@override
- _i4.Future<String> getExampleSource(_i8.GetExampleRequestWrapper? request) =>
+ _i5.Future<String> getExampleSource(_i9.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getExampleSource, [request]),
- returnValue: Future<String>.value('')) as _i4.Future<String>);
+ returnValue: Future<String>.value('')) as _i5.Future<String>);
@override
- _i4.Future<String> getExampleOutput(_i8.GetExampleRequestWrapper? request) =>
+ _i5.Future<String> getExampleOutput(_i9.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getExampleOutput, [request]),
- returnValue: Future<String>.value('')) as _i4.Future<String>);
+ returnValue: Future<String>.value('')) as _i5.Future<String>);
@override
- _i4.Future<String> getExampleLogs(_i8.GetExampleRequestWrapper? request) =>
+ _i5.Future<String> getExampleLogs(_i9.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getExampleLogs, [request]),
- returnValue: Future<String>.value('')) as _i4.Future<String>);
+ returnValue: Future<String>.value('')) as _i5.Future<String>);
@override
- _i4.Future<String> getExampleGraph(_i8.GetExampleRequestWrapper? request) =>
+ _i5.Future<String> getExampleGraph(_i9.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getExampleGraph, [request]),
- returnValue: Future<String>.value('')) as _i4.Future<String>);
+ returnValue: Future<String>.value('')) as _i5.Future<String>);
@override
- _i4.Future<_i2.ExampleModel> getExample(
- _i8.GetExampleRequestWrapper? request) =>
+ _i5.Future<_i2.ExampleModel> getExample(
+ _i9.GetExampleRequestWrapper? request) =>
(super.noSuchMethod(Invocation.method(#getExample, [request]),
returnValue:
Future<_i2.ExampleModel>.value(_FakeExampleModel_0()))
- as _i4.Future<_i2.ExampleModel>);
+ as _i5.Future<_i2.ExampleModel>);
+ @override
+ _i5.Future<_i3.GetSnippetResponse> getSnippet(
+ _i10.GetSnippetRequestWrapper? request) =>
+ (super.noSuchMethod(Invocation.method(#getSnippet, [request]),
+ returnValue: Future<_i3.GetSnippetResponse>.value(
+ _FakeGetSnippetResponse_1()))
+ as _i5.Future<_i3.GetSnippetResponse>);
+ @override
+ _i5.Future<String> saveSnippet(_i11.SaveSnippetRequestWrapper? request) =>
+ (super.noSuchMethod(Invocation.method(#saveSnippet, [request]),
+ returnValue: Future<String>.value('')) as _i5.Future<String>);
}
diff --git a/playground/frontend/test/pages/playground/states/mocks/request_mock.dart b/playground/frontend/test/pages/playground/states/mocks/request_mock.dart
index e6536897712..b08a81ebd55 100644
--- a/playground/frontend/test/pages/playground/states/mocks/request_mock.dart
+++ b/playground/frontend/test/pages/playground/states/mocks/request_mock.dart
@@ -37,7 +37,7 @@ final kGetExampleCodeResponseMock = GetExampleCodeResponse('test source');
final kOutputResponseMock = OutputResponse('test outputs');
final kRequestForExampleInfo =
- GetExampleRequestWrapper('SDK/Category/Name', SDK.java);
+ GetExampleRequestWrapper('SDK_PYTHON/Category/Name', SDK.python);
final kRequestDefaultExampleForJava = GetExampleRequestWrapper('', SDK.java);
final kRequestDefaultExampleForGo = GetExampleRequestWrapper('', SDK.go);
final kRequestDefaultExampleForPython =
diff --git a/playground/frontend/test/pages/playground/states/playground_state_test.dart b/playground/frontend/test/pages/playground/states/playground_state_test.dart
index d49e69d3017..7c2f7ee5bb3 100644
--- a/playground/frontend/test/pages/playground/states/playground_state_test.dart
+++ b/playground/frontend/test/pages/playground/states/playground_state_test.dart
@@ -17,16 +17,28 @@
*/
import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
import 'package:playground/modules/sdk/models/sdk.dart';
+import 'package:playground/pages/playground/states/example_loaders/examples_loader.dart';
+import 'package:playground/pages/playground/states/examples_state.dart';
import 'package:playground/pages/playground/states/playground_state.dart';
import 'mocks/example_mock.dart';
+import 'playground_state_test.mocks.dart';
+@GenerateMocks([ExamplesLoader, ExampleState])
void main() {
late PlaygroundState state;
+ final mockExamplesLoader = MockExamplesLoader();
+
+ when(mockExamplesLoader.load(any)).thenAnswer((_) async => 1);
setUp(() {
- state = PlaygroundState();
+ state = PlaygroundState(
+ examplesLoader: MockExamplesLoader(),
+ exampleState: MockExampleState(),
+ );
});
test('Initial value of SDK field should be java', () {
@@ -80,13 +92,12 @@ void main() {
test(
'Playground state setExample should update source and example and notify all listeners',
() {
- final state = PlaygroundState(sdk: SDK.go);
state.addListener(() {
expect(state.sdk, SDK.go);
- expect(state.source, exampleMock1.source);
- expect(state.selectedExample, exampleMock1);
+ expect(state.source, exampleMockGo.source);
+ expect(state.selectedExample, exampleMockGo);
});
- state.setExample(exampleMock1);
+ state.setExample(exampleMockGo);
},
);
@@ -100,8 +111,8 @@ void main() {
test(
'Playground state reset should reset source to example notify all listeners',
() {
- final state = PlaygroundState(sdk: SDK.go, selectedExample: exampleMock1);
- state.setSource('source');
+ state.setExample(exampleMock1);
+ state.source = 'source';
state.addListener(() {
expect(state.source, exampleMock1.source);
});
diff --git a/playground/frontend/test/pages/playground/states/playground_state_test.mocks.dart b/playground/frontend/test/pages/playground/states/playground_state_test.mocks.dart
new file mode 100644
index 00000000000..4cd040cc8a4
--- /dev/null
+++ b/playground/frontend/test/pages/playground/states/playground_state_test.mocks.dart
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+// Mocks generated by Mockito 5.2.0 from annotations
+// in playground/test/pages/playground/states/playground_state_test.dart.
+// Do not manually edit this file.
+
+import 'dart:async' as _i5;
+import 'dart:ui' as _i11;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:playground/modules/examples/models/category_model.dart' as _i9;
+import 'package:playground/modules/examples/models/example_loading_descriptors/examples_loading_descriptor.dart'
+ as _i6;
+import 'package:playground/modules/examples/models/example_model.dart' as _i2;
+import 'package:playground/modules/examples/repositories/models/shared_file_model.dart'
+ as _i10;
+import 'package:playground/modules/sdk/models/sdk.dart' as _i8;
+import 'package:playground/pages/playground/states/example_loaders/examples_loader.dart'
+ as _i3;
+import 'package:playground/pages/playground/states/examples_state.dart' as _i7;
+import 'package:playground/pages/playground/states/playground_state.dart'
+ as _i4;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+
+class _FakeExampleModel_0 extends _i1.Fake implements _i2.ExampleModel {}
+
+/// A class which mocks [ExamplesLoader].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockExamplesLoader extends _i1.Mock implements _i3.ExamplesLoader {
+ MockExamplesLoader() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ void setPlaygroundState(_i4.PlaygroundState? value) =>
+ super.noSuchMethod(Invocation.method(#setPlaygroundState, [value]),
+ returnValueForMissingStub: null);
+ @override
+ _i5.Future<void> load(_i6.ExamplesLoadingDescriptor? descriptor) =>
+ (super.noSuchMethod(Invocation.method(#load, [descriptor]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+}
+
+/// A class which mocks [ExampleState].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockExampleState extends _i1.Mock implements _i7.ExampleState {
+ MockExampleState() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ set sdkCategories(Map<_i8.SDK, List<_i9.CategoryModel>>? _sdkCategories) =>
+ super.noSuchMethod(Invocation.setter(#sdkCategories, _sdkCategories),
+ returnValueForMissingStub: null);
+ @override
+ Map<_i8.SDK, _i2.ExampleModel> get defaultExamplesMap =>
+ (super.noSuchMethod(Invocation.getter(#defaultExamplesMap),
+ returnValue: <_i8.SDK, _i2.ExampleModel>{})
+ as Map<_i8.SDK, _i2.ExampleModel>);
+ @override
+ set defaultExamplesMap(Map<_i8.SDK, _i2.ExampleModel>? _defaultExamplesMap) =>
+ super.noSuchMethod(
+ Invocation.setter(#defaultExamplesMap, _defaultExamplesMap),
+ returnValueForMissingStub: null);
+ @override
+ set defaultExample(_i2.ExampleModel? _defaultExample) =>
+ super.noSuchMethod(Invocation.setter(#defaultExample, _defaultExample),
+ returnValueForMissingStub: null);
+ @override
+ bool get isSelectorOpened =>
+ (super.noSuchMethod(Invocation.getter(#isSelectorOpened),
+ returnValue: false) as bool);
+ @override
+ set isSelectorOpened(bool? _isSelectorOpened) => super.noSuchMethod(
+ Invocation.setter(#isSelectorOpened, _isSelectorOpened),
+ returnValueForMissingStub: null);
+ @override
+ _i5.Future<void> get allExamplesFuture =>
+ (super.noSuchMethod(Invocation.getter(#allExamplesFuture),
+ returnValue: Future<void>.value()) as _i5.Future<void>);
+ @override
+ bool get hasExampleCatalog =>
+ (super.noSuchMethod(Invocation.getter(#hasExampleCatalog),
+ returnValue: false) as bool);
+ @override
+ bool get hasListeners =>
+ (super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false)
+ as bool);
+ @override
+ dynamic setSdkCategories(Map<_i8.SDK, List<_i9.CategoryModel>>? map) =>
+ super.noSuchMethod(Invocation.method(#setSdkCategories, [map]));
+ @override
+ List<_i9.CategoryModel>? getCategories(_i8.SDK? sdk) =>
+ (super.noSuchMethod(Invocation.method(#getCategories, [sdk]))
+ as List<_i9.CategoryModel>?);
+ @override
+ _i5.Future<String> getExampleOutput(String? id, _i8.SDK? sdk) =>
+ (super.noSuchMethod(Invocation.method(#getExampleOutput, [id, sdk]),
+ returnValue: Future<String>.value('')) as _i5.Future<String>);
+ @override
+ _i5.Future<String> getExampleSource(String? id, _i8.SDK? sdk) =>
+ (super.noSuchMethod(Invocation.method(#getExampleSource, [id, sdk]),
+ returnValue: Future<String>.value('')) as _i5.Future<String>);
+ @override
+ _i5.Future<_i2.ExampleModel> getExample(String? path, _i8.SDK? sdk) =>
+ (super.noSuchMethod(Invocation.method(#getExample, [path, sdk]),
+ returnValue:
+ Future<_i2.ExampleModel>.value(_FakeExampleModel_0()))
+ as _i5.Future<_i2.ExampleModel>);
+ @override
+ _i5.Future<String> getExampleLogs(String? id, _i8.SDK? sdk) =>
+ (super.noSuchMethod(Invocation.method(#getExampleLogs, [id, sdk]),
+ returnValue: Future<String>.value('')) as _i5.Future<String>);
+ @override
+ _i5.Future<String> getExampleGraph(String? id, _i8.SDK? sdk) =>
+ (super.noSuchMethod(Invocation.method(#getExampleGraph, [id, sdk]),
+ returnValue: Future<String>.value('')) as _i5.Future<String>);
+ @override
+ _i5.Future<_i2.ExampleModel> loadSharedExample(String? id) =>
+ (super.noSuchMethod(Invocation.method(#loadSharedExample, [id]),
+ returnValue:
+ Future<_i2.ExampleModel>.value(_FakeExampleModel_0()))
+ as _i5.Future<_i2.ExampleModel>);
+ @override
+ _i5.Future<String> getSnippetId(
+ {List<_i10.SharedFile>? files,
+ _i8.SDK? sdk,
+ String? pipelineOptions}) =>
+ (super.noSuchMethod(
+ Invocation.method(#getSnippetId, [],
+ {#files: files, #sdk: sdk, #pipelineOptions: pipelineOptions}),
+ returnValue: Future<String>.value('')) as _i5.Future<String>);
+ @override
+ _i5.Future<_i2.ExampleModel> loadExampleInfo(_i2.ExampleModel? example) =>
+ (super.noSuchMethod(Invocation.method(#loadExampleInfo, [example]),
+ returnValue:
+ Future<_i2.ExampleModel>.value(_FakeExampleModel_0()))
+ as _i5.Future<_i2.ExampleModel>);
+ @override
+ _i5.Future<void> loadDefaultExamples() =>
+ (super.noSuchMethod(Invocation.method(#loadDefaultExamples, []),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ @override
+ _i5.Future<void> loadDefaultExamplesIfNot() =>
+ (super.noSuchMethod(Invocation.method(#loadDefaultExamplesIfNot, []),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ @override
+ _i5.Future<_i2.ExampleModel?> getCatalogExampleByPath(String? path) =>
+ (super.noSuchMethod(Invocation.method(#getCatalogExampleByPath, [path]),
+ returnValue: Future<_i2.ExampleModel?>.value())
+ as _i5.Future<_i2.ExampleModel?>);
+ @override
+ void addListener(_i11.VoidCallback? listener) =>
+ super.noSuchMethod(Invocation.method(#addListener, [listener]),
+ returnValueForMissingStub: null);
+ @override
+ void removeListener(_i11.VoidCallback? listener) =>
+ super.noSuchMethod(Invocation.method(#removeListener, [listener]),
+ returnValueForMissingStub: null);
+ @override
+ void dispose() => super.noSuchMethod(Invocation.method(#dispose, []),
+ returnValueForMissingStub: null);
+ @override
+ void notifyListeners() =>
+ super.noSuchMethod(Invocation.method(#notifyListeners, []),
+ returnValueForMissingStub: null);
+}