From 7c2303343812c3d0886dcb4bf2b10c3b28f9ea0a Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 21 Oct 2022 17:32:30 +0600 Subject: [PATCH 01/65] Content tree navigation (#23593) Unit content navigation (#23593) Update URL on node click (#23593) Active unit color (#23593) removeListener in unit (#23593) First unit is opened on group title click (#23593) WIP by Alexey Inkin (#23593) selectedUnitColor (#23593) Unit borderRadius (#23593) RegExp todo (#23593) added referenced collection package to remove warning (#23593) small refinement (#23593) expand on group tap, padding, openNode (#23593) group expansion bug fix (#23593) selected & unselected progress indicators (#23593) --- .../frontend/lib/components/filler_text.dart | 29 ---------- .../frontend/lib/models/content_tree.dart | 14 ++++- .../frontend/lib/models/group.dart | 29 +++++++--- .../frontend/lib/models/module.dart | 29 ++++++---- .../frontend/lib/models/node.dart | 20 +++++-- .../frontend/lib/models/parent_node.dart | 18 ++++++ .../frontend/lib/models/unit.dart | 15 ++++- .../pages/tour/controllers/content_tree.dart | 57 +++++++++++++++++-- .../frontend/lib/pages/tour/path.dart | 9 ++- .../frontend/lib/pages/tour/state.dart | 2 + .../lib/pages/tour/widgets/group.dart | 32 +++++++++-- .../lib/pages/tour/widgets/group_title.dart | 5 +- .../lib/pages/tour/widgets/module.dart | 2 +- .../tour/widgets/tour_progress_indicator.dart | 18 +++++- .../frontend/lib/pages/tour/widgets/unit.dart | 42 ++++++++++++-- .../frontend/lib/pages/welcome/screen.dart | 3 - learning/tour-of-beam/frontend/pubspec.lock | 4 +- learning/tour-of-beam/frontend/pubspec.yaml | 1 + .../lib/src/constants/colors.dart | 46 ++++++++------- .../lib/src/theme/theme.dart | 26 +++++++++ 20 files changed, 300 insertions(+), 101 deletions(-) delete mode 100644 learning/tour-of-beam/frontend/lib/components/filler_text.dart diff --git a/learning/tour-of-beam/frontend/lib/components/filler_text.dart b/learning/tour-of-beam/frontend/lib/components/filler_text.dart deleted file mode 100644 index ca6099e6d9de..000000000000 --- a/learning/tour-of-beam/frontend/lib/components/filler_text.dart +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import 'package:flutter/material.dart'; - -class FillerText extends StatelessWidget { - final int width; - const FillerText({required this.width}); - - @override - Widget build(BuildContext context) { - return Text(''.padRight(width, 'Just a filler text. ')); - } -} diff --git a/learning/tour-of-beam/frontend/lib/models/content_tree.dart b/learning/tour-of-beam/frontend/lib/models/content_tree.dart index 4c3ba29378ab..14949cc157fa 100644 --- a/learning/tour-of-beam/frontend/lib/models/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/models/content_tree.dart @@ -18,15 +18,25 @@ import '../repositories/models/get_content_tree_response.dart'; import 'module.dart'; +import 'node.dart'; +import 'parent_node.dart'; -class ContentTreeModel { +class ContentTreeModel extends ParentNodeModel { final String sdkId; final List modules; + @override + List get nodes => modules; + const ContentTreeModel({ required this.sdkId, required this.modules, - }); + }) : super( + id: sdkId, + parent: null, + title: '', + nodes: modules, + ); ContentTreeModel.fromResponse(GetContentTreeResponse response) : this( diff --git a/learning/tour-of-beam/frontend/lib/models/group.dart b/learning/tour-of-beam/frontend/lib/models/group.dart index 22086e6303e8..ba1d4047a574 100644 --- a/learning/tour-of-beam/frontend/lib/models/group.dart +++ b/learning/tour-of-beam/frontend/lib/models/group.dart @@ -23,15 +23,28 @@ import 'parent_node.dart'; class GroupModel extends ParentNodeModel { const GroupModel({ required super.id, - required super.title, required super.nodes, + required super.parent, + required super.title, }); - GroupModel.fromResponse(GroupResponseModel group) - : super( - id: group.id, - title: group.title, - nodes: - group.nodes.map(NodeModel.fromResponse).toList(growable: false), - ); + factory GroupModel.fromResponse( + GroupResponseModel groupResponse, + ParentNodeModel parent, + ) { + final group = GroupModel( + id: groupResponse.id, + nodes: [], + parent: parent, + title: groupResponse.title, + ); + + group.nodes.addAll( + groupResponse.nodes.map( + (node) => NodeModel.fromResponse(node, group), + ), + ); + + return group; + } } diff --git a/learning/tour-of-beam/frontend/lib/models/module.dart b/learning/tour-of-beam/frontend/lib/models/module.dart index 81f8c1b6d613..eb1f7e50633c 100644 --- a/learning/tour-of-beam/frontend/lib/models/module.dart +++ b/learning/tour-of-beam/frontend/lib/models/module.dart @@ -27,18 +27,27 @@ class ModuleModel extends ParentNodeModel { const ModuleModel({ required super.id, - required super.title, required super.nodes, + required super.parent, + required super.title, required this.complexity, }); - ModuleModel.fromResponse(ModuleResponseModel module) - : complexity = module.complexity, - super( - id: module.id, - title: module.title, - nodes: module.nodes - .map(NodeModel.fromResponse) - .toList(growable: false), - ); + factory ModuleModel.fromResponse(ModuleResponseModel moduleResponse) { + final module = ModuleModel( + complexity: moduleResponse.complexity, + nodes: [], + id: moduleResponse.id, + parent: null, + title: moduleResponse.title, + ); + + module.nodes.addAll( + moduleResponse.nodes.map( + (node) => NodeModel.fromResponse(node, module), + ), + ); + + return module; + } } diff --git a/learning/tour-of-beam/frontend/lib/models/node.dart b/learning/tour-of-beam/frontend/lib/models/node.dart index d13ceea2d282..7a653de1e3ad 100644 --- a/learning/tour-of-beam/frontend/lib/models/node.dart +++ b/learning/tour-of-beam/frontend/lib/models/node.dart @@ -19,15 +19,18 @@ import '../repositories/models/node.dart'; import '../repositories/models/node_type_enum.dart'; import 'group.dart'; +import 'parent_node.dart'; import 'unit.dart'; abstract class NodeModel { final String id; final String title; + final NodeModel? parent; const NodeModel({ required this.id, required this.title, + required this.parent, }); /// Constructs nodes from the response data. @@ -36,20 +39,27 @@ abstract class NodeModel { /// because they come from a golang backend which does not /// support inheritance, and so they use an extra layer of composition /// which is inconvenient in Flutter. - static List fromMaps(List json) { + static List fromMaps(List json, ParentNodeModel parent) { return json .cast>() .map(NodeResponseModel.fromJson) - .map(fromResponse) + .map((nodeResponse) => fromResponse(nodeResponse, parent)) .toList(); } - static NodeModel fromResponse(NodeResponseModel node) { + static NodeModel fromResponse( + NodeResponseModel node, + ParentNodeModel parent, + ) { switch (node.type) { case NodeType.group: - return GroupModel.fromResponse(node.group!); + return GroupModel.fromResponse(node.group!, parent); case NodeType.unit: - return UnitModel.fromResponse(node.unit!); + return UnitModel.fromResponse(node.unit!, parent); } } + + NodeModel getFirstUnit(); + + NodeModel? getNodeByTreeIds(List treeIds); } diff --git a/learning/tour-of-beam/frontend/lib/models/parent_node.dart b/learning/tour-of-beam/frontend/lib/models/parent_node.dart index 0271cfb9508f..53f3c7a17667 100644 --- a/learning/tour-of-beam/frontend/lib/models/parent_node.dart +++ b/learning/tour-of-beam/frontend/lib/models/parent_node.dart @@ -16,6 +16,8 @@ * limitations under the License. */ +import 'package:collection/collection.dart'; + import 'node.dart'; abstract class ParentNodeModel extends NodeModel { @@ -23,7 +25,23 @@ abstract class ParentNodeModel extends NodeModel { const ParentNodeModel({ required super.id, + required super.parent, required super.title, required this.nodes, }); + + @override + NodeModel getFirstUnit() => nodes[0].getFirstUnit(); + + @override + NodeModel? getNodeByTreeIds(List treeIds) { + final firstId = treeIds.firstOrNull; + final child = nodes.firstWhereOrNull((node) => node.id == firstId); + + if (child == null) { + return null; + } + + return child.getNodeByTreeIds(treeIds.sublist(1)); + } } diff --git a/learning/tour-of-beam/frontend/lib/models/unit.dart b/learning/tour-of-beam/frontend/lib/models/unit.dart index 48b55af33d15..eb2e158ddf62 100644 --- a/learning/tour-of-beam/frontend/lib/models/unit.dart +++ b/learning/tour-of-beam/frontend/lib/models/unit.dart @@ -18,8 +18,19 @@ import '../repositories/models/unit.dart'; import 'node.dart'; +import 'parent_node.dart'; class UnitModel extends NodeModel { - UnitModel.fromResponse(UnitResponseModel unit) - : super(id: unit.id, title: unit.title); + UnitModel.fromResponse(UnitResponseModel unit, ParentNodeModel parent) + : super( + id: unit.id, + parent: parent, + title: unit.title, + ); + + @override + NodeModel getFirstUnit() => this; + + @override + NodeModel? getNodeByTreeIds(List treeIds) => this; } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart index dc5fc5a15ceb..6193f0b8ce09 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart @@ -17,33 +17,82 @@ */ import 'package:flutter/widgets.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; +import '../../../cache/content_tree.dart'; +import '../../../models/group.dart'; import '../../../models/node.dart'; +import '../../../models/unit.dart'; class ContentTreeController extends ChangeNotifier { String _sdkId; List _treeIds; NodeModel? _currentNode; + final _contentTreeCache = GetIt.instance.get(); + final expandedIds = {}; ContentTreeController({ required String initialSdkId, List initialTreeIds = const [], }) : _sdkId = initialSdkId, - _treeIds = initialTreeIds; + _treeIds = initialTreeIds { + expandedIds.addAll(initialTreeIds); + _contentTreeCache.addListener(_onContentTreeCacheChange); + _onContentTreeCacheChange(); + } Sdk get sdk => Sdk.parseOrCreate(_sdkId); String get sdkId => _sdkId; List get treeIds => _treeIds; NodeModel? get currentNode => _currentNode; - void onNodeTap(NodeModel node) { + void openNode(NodeModel node) { + if (!expandedIds.contains(node.id)) { + expandedIds.add(node.id); + } + if (node == _currentNode) { return; } - _currentNode = node; - // TODO(alexeyinkin): Set _treeIds from node. + if (node is GroupModel) { + openNode(node.nodes.first); + } else if (node is UnitModel) { + _currentNode = node; + } + + if (_currentNode != null) { + _treeIds = _getNodeAncestors(_currentNode!, [_currentNode!.id]); + } + notifyListeners(); + } + + List _getNodeAncestors(NodeModel node, List ancestors) { + if (node.parent != null) { + ancestors.add(node.parent!.id); + return _getNodeAncestors(node.parent!, ancestors); + } else { + return ancestors.reversed.toList(); + } + } + + void _onContentTreeCacheChange() { + final contentTree = _contentTreeCache.getContentTree(_sdkId); + if (contentTree == null) { + return; + } + + openNode( + contentTree.getNodeByTreeIds(_treeIds) ?? contentTree.getFirstUnit(), + ); + notifyListeners(); } + + @override + void dispose() { + _contentTreeCache.removeListener(_onContentTreeCacheChange); + super.dispose(); + } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/path.dart b/learning/tour-of-beam/frontend/lib/pages/tour/path.dart index 5f8971852f9f..07dd386bdfcb 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/path.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/path.dart @@ -26,7 +26,7 @@ class TourPath extends PagePath { final String sdkId; final List treeIds; - static final _regExp = RegExp(r'^/tour/([a-z]+)(/[/-a-zA-Z0-9]+)?$'); + static final _regExp = RegExp(r'^/tour/([a-z]+)((/[-a-zA-Z0-9]+)*)$'); TourPath({ required this.sdkId, @@ -47,7 +47,12 @@ class TourPath extends PagePath { if (matches == null) return null; final sdkId = matches[1] ?? (throw Error()); - final treeIds = matches[2]?.split('/') ?? const []; + final treeIdsString = matches[2]; + + final treeIds = (treeIdsString == null) + ? const [] + // TODO(nausharipov): use RegExp to remove the slash + : treeIdsString.substring(1).split('/'); return TourPath( sdkId: sdkId, diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index ae8fc0e1e706..e709839e915e 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -44,6 +44,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { playgroundController = _createPlaygroundController(initialSdkId) { contentTreeController.addListener(_onChanged); _unitContentCache.addListener(_onChanged); + _onChanged(); } @override @@ -53,6 +54,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { ); void _onChanged() { + emitPathChanged(); final currentNode = contentTreeController.currentNode; if (currentNode is UnitModel) { final content = _unitContentCache.getUnitContent( diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart index bdebcfc507be..2be9d09e218b 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart @@ -25,7 +25,7 @@ import '../controllers/content_tree.dart'; import 'group_nodes.dart'; import 'group_title.dart'; -class GroupWidget extends StatelessWidget { +class GroupWidget extends StatefulWidget { final GroupModel group; final ContentTreeController contentTreeController; @@ -34,22 +34,44 @@ class GroupWidget extends StatelessWidget { required this.contentTreeController, }); + @override + State createState() => _GroupWidgetState(); +} + +class _GroupWidgetState extends State { @override Widget build(BuildContext context) { + final isExpanded = + widget.contentTreeController.expandedIds.contains(widget.group.id); + return ExpansionTileWrapper( ExpansionTile( + key: Key('${widget.group.id}$isExpanded'), + initiallyExpanded: isExpanded, tilePadding: EdgeInsets.zero, + onExpansionChanged: (expand) { + /// Since expandedIds is also used for expansion, it needs to be + /// updated to prevent the tile to stay collapsed on title tap. + if (!expand) { + widget.contentTreeController.expandedIds.remove(widget.group.id); + setState(() {}); + } + }, title: GroupTitleWidget( - group: group, - onTap: () => contentTreeController.onNodeTap(group), + group: widget.group, + onTap: () { + widget.contentTreeController.openNode(widget.group); + // Couldn't make it rebuild reliably with AnimatedBuilder + setState(() {}); + }, ), childrenPadding: const EdgeInsets.only( left: BeamSizes.size24, ), children: [ GroupNodesWidget( - nodes: group.nodes, - contentTreeController: contentTreeController, + nodes: widget.group.nodes, + contentTreeController: widget.contentTreeController, ), ], ), diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart index a25c5498bd92..974199946cba 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart @@ -38,7 +38,10 @@ class GroupTitleWidget extends StatelessWidget { onTap: onTap, child: Row( children: [ - TourProgressIndicator(assetPath: Assets.svg.unitProgress0), + TourProgressIndicator( + assetPath: Assets.svg.unitProgress0, + isSelected: false, + ), Text( group.title, style: Theme.of(context).textTheme.headlineMedium, diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/module.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/module.dart index 886e9f98d863..b01987bf0a7c 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/module.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/module.dart @@ -39,7 +39,7 @@ class ModuleWidget extends StatelessWidget { children: [ ModuleTitleWidget( module: module, - onTap: () => contentTreeController.onNodeTap(module), + onTap: () => contentTreeController.openNode(module), ), ...module.nodes .map( diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart index 6184a22a9d4f..c600317ded31 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart @@ -21,9 +21,14 @@ import 'package:flutter_svg/svg.dart'; import 'package:playground_components/playground_components.dart'; class TourProgressIndicator extends StatelessWidget { + // TODO(nausharipov): replace assetPath with progress enum final String assetPath; + final bool isSelected; - const TourProgressIndicator({required this.assetPath}); + const TourProgressIndicator({ + required this.assetPath, + required this.isSelected, + }); @override Widget build(BuildContext context) { @@ -32,7 +37,16 @@ class TourProgressIndicator extends StatelessWidget { left: BeamSizes.size4, right: BeamSizes.size8, ), - child: SvgPicture.asset(assetPath), + child: SvgPicture.asset( + assetPath, + color: isSelected + ? Theme.of(context) + .extension()! + .selectedProgressColor + : Theme.of(context) + .extension()! + .unselectedProgressColor, + ), ); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart index 914361a347a4..29ccebd8f3d0 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart @@ -24,7 +24,7 @@ import '../../../models/unit.dart'; import '../controllers/content_tree.dart'; import 'tour_progress_indicator.dart'; -class UnitWidget extends StatelessWidget { +class UnitWidget extends StatefulWidget { final UnitModel unit; final ContentTreeController contentTreeController; @@ -33,16 +33,48 @@ class UnitWidget extends StatelessWidget { required this.contentTreeController, }); + @override + State createState() => _UnitWidgetState(); +} + +class _UnitWidgetState extends State { + @override + void initState() { + super.initState(); + widget.contentTreeController.addListener(_rebuild); + } + + @override + void dispose() { + widget.contentTreeController.removeListener(_rebuild); + super.dispose(); + } + + void _rebuild() { + setState(() {}); + } + @override Widget build(BuildContext context) { + final bool isSelected = + widget.contentTreeController.currentNode?.id == widget.unit.id; return ClickableWidget( - onTap: () => contentTreeController.onNodeTap(unit), - child: Padding( + onTap: () => widget.contentTreeController.openNode(widget.unit), + child: Container( + decoration: BoxDecoration( + color: isSelected ? Theme.of(context).selectedRowColor : null, + borderRadius: BorderRadius.circular(BeamSizes.size3), + ), padding: const EdgeInsets.symmetric(vertical: BeamSizes.size10), child: Row( children: [ - TourProgressIndicator(assetPath: Assets.svg.unitProgress0), - Expanded(child: Text(unit.title)), + TourProgressIndicator( + assetPath: Assets.svg.unitProgress0, + isSelected: isSelected, + ), + Expanded( + child: Text(widget.unit.title), + ), ], ), ), diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart index 421593562672..af6e91969bd2 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart @@ -24,7 +24,6 @@ import 'package:playground_components/playground_components.dart'; import '../../components/builders/content_tree.dart'; import '../../components/builders/sdks.dart'; -import '../../components/filler_text.dart'; import '../../components/scaffold.dart'; import '../../constants/sizes.dart'; import '../../generated/assets.gen.dart'; @@ -397,7 +396,6 @@ class _ModuleBody extends StatelessWidget { padding: _modulePadding, child: Column( children: [ - const FillerText(width: 20), const SizedBox(height: BeamSizes.size16), Divider( color: themeData.dividerColor, @@ -416,7 +414,6 @@ class _LastModuleBody extends StatelessWidget { return Container( margin: _moduleLeftMargin, padding: _modulePadding, - child: const FillerText(width: 20), ); } } diff --git a/learning/tour-of-beam/frontend/pubspec.lock b/learning/tour-of-beam/frontend/pubspec.lock index 9983b9bb5304..6b49ce6e37bc 100644 --- a/learning/tour-of-beam/frontend/pubspec.lock +++ b/learning/tour-of-beam/frontend/pubspec.lock @@ -156,7 +156,7 @@ packages: source: hosted version: "4.2.0" collection: - dependency: transitive + dependency: "direct main" description: name: collection url: "https://pub.dartlang.org" @@ -278,7 +278,7 @@ packages: name: flutter_code_editor url: "https://pub.dartlang.org" source: hosted - version: "0.1.1" + version: "0.1.3" flutter_driver: dependency: transitive description: flutter diff --git a/learning/tour-of-beam/frontend/pubspec.yaml b/learning/tour-of-beam/frontend/pubspec.yaml index a6e829542e0c..a8f4fd9a4ce7 100644 --- a/learning/tour-of-beam/frontend/pubspec.yaml +++ b/learning/tour-of-beam/frontend/pubspec.yaml @@ -28,6 +28,7 @@ environment: dependencies: app_state: ^0.8.1 + collection: ^1.16.0 easy_localization: ^3.0.1 easy_localization_ext: ^0.1.0 easy_localization_loader: ^1.0.0 diff --git a/playground/frontend/playground_components/lib/src/constants/colors.dart b/playground/frontend/playground_components/lib/src/constants/colors.dart index 447d564056ed..6db92295c16a 100644 --- a/playground/frontend/playground_components/lib/src/constants/colors.dart +++ b/playground/frontend/playground_components/lib/src/constants/colors.dart @@ -36,45 +36,51 @@ class BeamColors { class BeamGraphColors { static const node = BeamColors.grey3; - static const border = Color(0xFF45454E); + static const border = Color(0xff45454E); static const edge = BeamLightThemeColors.primary; } class BeamNotificationColors { - static const error = Color(0xFFE54545); - static const info = Color(0xFF3E67F6); - static const success = Color(0xFF37AC66); - static const warning = Color(0xFFEEAB00); + static const error = Color(0xffE54545); + static const info = Color(0xff3E67F6); + static const success = Color(0xff37AC66); + static const warning = Color(0xffEEAB00); } class BeamLightThemeColors { - static const border = Color(0xFFE5E5E5); + static const border = Color(0xffE5E5E5); static const primaryBackground = BeamColors.white; static const secondaryBackground = Color(0xffFCFCFC); + static const selectedUnitColor = Color(0xffE6E7E9); + static const selectedProgressColor = BeamColors.grey3; + static const unselectedProgressColor = selectedUnitColor; static const grey = Color(0xffE5E5E5); - static const listBackground = Color(0xFFA0A4AB); + static const listBackground = BeamColors.grey3; static const text = BeamColors.darkBlue; static const primary = Color(0xffE74D1A); - static const icon = Color(0xFFA0A4AB); + static const icon = BeamColors.grey3; - static const code1 = Color(0xFFDA2833); - static const code2 = Color(0xFF5929B4); - static const codeComment = Color(0xFF4C6B60); - static const codeBackground = Color(0xFFFEF6F3); + static const code1 = Color(0xffDA2833); + static const code2 = Color(0xff5929B4); + static const codeComment = Color(0xff4C6B60); + static const codeBackground = Color(0xffFEF6F3); } class BeamDarkThemeColors { - static const border = Color(0xFFA0A4AB); + static const border = BeamColors.grey3; static const primaryBackground = Color(0xff18181B); static const secondaryBackground = BeamColors.darkGrey; + static const selectedUnitColor = Color(0xff626267); + static const selectedProgressColor = BeamColors.grey1; + static const unselectedProgressColor = selectedUnitColor; static const grey = Color(0xff3F3F46); - static const listBackground = Color(0xFF606772); - static const text = Color(0xffFFFFFF); + static const listBackground = Color(0xff606772); + static const text = Color(0xffffffff); static const primary = Color(0xffF26628); - static const icon = Color(0xFF606772); + static const icon = Color(0xff606772); - static const code1 = Color(0xFFDA2833); - static const code2 = Color(0xFF5929B4); - static const codeComment = Color(0xFF4C6B60); - static const codeBackground = Color(0xFF231B1B); + static const code1 = Color(0xffDA2833); + static const code2 = Color(0xff5929B4); + static const codeComment = Color(0xff4C6B60); + static const codeBackground = Color(0xff231B1B); } diff --git a/playground/frontend/playground_components/lib/src/theme/theme.dart b/playground/frontend/playground_components/lib/src/theme/theme.dart index 14c811abe931..287eef0a14f3 100644 --- a/playground/frontend/playground_components/lib/src/theme/theme.dart +++ b/playground/frontend/playground_components/lib/src/theme/theme.dart @@ -32,6 +32,9 @@ class BeamThemeExtension extends ThemeExtension { final Color primaryBackgroundTextColor; final Color lightGreyBackgroundTextColor; final Color secondaryBackgroundColor; + // TODO(nausharipov): simplify new color addition + final Color selectedProgressColor; + final Color unselectedProgressColor; final Color codeBackgroundColor; final TextStyle codeRootStyle; @@ -50,6 +53,8 @@ class BeamThemeExtension extends ThemeExtension { required this.codeBackgroundColor, required this.codeRootStyle, required this.codeTheme, + required this.selectedProgressColor, + required this.unselectedProgressColor, }); @override @@ -64,6 +69,8 @@ class BeamThemeExtension extends ThemeExtension { Color? codeBackgroundColor, TextStyle? codeRootStyle, CodeThemeData? codeTheme, + Color? selectedProgressColor, + Color? unselectedProgressColor, }) { return BeamThemeExtension( borderColor: borderColor ?? this.borderColor, @@ -79,6 +86,10 @@ class BeamThemeExtension extends ThemeExtension { codeBackgroundColor: codeBackgroundColor ?? this.codeBackgroundColor, codeRootStyle: codeRootStyle ?? this.codeRootStyle, codeTheme: codeTheme ?? this.codeTheme, + selectedProgressColor: + selectedProgressColor ?? this.selectedProgressColor, + unselectedProgressColor: + unselectedProgressColor ?? this.unselectedProgressColor, ); } @@ -104,6 +115,13 @@ class BeamThemeExtension extends ThemeExtension { Color.lerp(codeBackgroundColor, other?.codeBackgroundColor, t)!, codeRootStyle: TextStyle.lerp(codeRootStyle, other?.codeRootStyle, t)!, codeTheme: t == 0.0 ? codeTheme : other?.codeTheme ?? codeTheme, + selectedProgressColor: + Color.lerp(selectedProgressColor, other?.selectedProgressColor, t)!, + unselectedProgressColor: Color.lerp( + unselectedProgressColor, + other?.unselectedProgressColor, + t, + )!, ); } } @@ -121,6 +139,7 @@ final kLightTheme = ThemeData( ), primaryColor: BeamLightThemeColors.primary, scaffoldBackgroundColor: BeamLightThemeColors.secondaryBackground, + selectedRowColor: BeamLightThemeColors.selectedUnitColor, tabBarTheme: _getTabBarTheme( textColor: BeamLightThemeColors.text, indicatorColor: BeamLightThemeColors.primary, @@ -136,6 +155,8 @@ final kLightTheme = ThemeData( lightGreyBackgroundTextColor: BeamColors.black, markdownStyle: _getMarkdownStyle(Brightness.light), secondaryBackgroundColor: BeamLightThemeColors.secondaryBackground, + selectedProgressColor: BeamLightThemeColors.selectedProgressColor, + unselectedProgressColor: BeamLightThemeColors.unselectedProgressColor, codeBackgroundColor: BeamLightThemeColors.codeBackground, codeRootStyle: GoogleFonts.sourceCodePro( color: BeamLightThemeColors.text, @@ -194,6 +215,7 @@ final kDarkTheme = ThemeData( ), primaryColor: BeamDarkThemeColors.primary, scaffoldBackgroundColor: BeamDarkThemeColors.secondaryBackground, + selectedRowColor: BeamDarkThemeColors.selectedUnitColor, tabBarTheme: _getTabBarTheme( textColor: BeamDarkThemeColors.text, indicatorColor: BeamDarkThemeColors.primary, @@ -209,6 +231,8 @@ final kDarkTheme = ThemeData( lightGreyBackgroundTextColor: BeamColors.black, markdownStyle: _getMarkdownStyle(Brightness.dark), secondaryBackgroundColor: BeamDarkThemeColors.secondaryBackground, + selectedProgressColor: BeamDarkThemeColors.selectedProgressColor, + unselectedProgressColor: BeamDarkThemeColors.unselectedProgressColor, codeBackgroundColor: BeamDarkThemeColors.codeBackground, codeRootStyle: GoogleFonts.sourceCodePro( color: BeamDarkThemeColors.text, @@ -396,8 +420,10 @@ MarkdownStyleSheet _getMarkdownStyle(Brightness brightness) { return MarkdownStyleSheet( p: textTheme.bodyMedium, + pPadding: EdgeInsets.only(top: BeamSizes.size2), h1: textTheme.headlineLarge, h3: textTheme.headlineMedium, + h3Padding: EdgeInsets.only(top: BeamSizes.size4), code: GoogleFonts.sourceCodePro( color: textColor, backgroundColor: BeamColors.transparent, From 5978d374b850c3c1b343cd92bf00d0f90af55958 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 4 Nov 2022 17:25:35 +0300 Subject: [PATCH 02/65] AnimatedBuilders instead of StatefulWidgets in unit & group (#23593) --- .../pages/tour/controllers/content_tree.dart | 5 ++ .../lib/pages/tour/widgets/group.dart | 73 +++++++++---------- .../frontend/lib/pages/tour/widgets/unit.dart | 69 +++++++----------- 3 files changed, 67 insertions(+), 80 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart index 6193f0b8ce09..77d355f13fad 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart @@ -68,6 +68,11 @@ class ContentTreeController extends ChangeNotifier { notifyListeners(); } + void markGroupAsCollapsed(GroupModel group) { + expandedIds.remove(group.id); + notifyListeners(); + } + List _getNodeAncestors(NodeModel node, List ancestors) { if (node.parent != null) { ancestors.add(node.parent!.id); diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart index 2be9d09e218b..1ea4374b71f2 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart @@ -25,7 +25,7 @@ import '../controllers/content_tree.dart'; import 'group_nodes.dart'; import 'group_title.dart'; -class GroupWidget extends StatefulWidget { +class GroupWidget extends StatelessWidget { final GroupModel group; final ContentTreeController contentTreeController; @@ -34,47 +34,44 @@ class GroupWidget extends StatefulWidget { required this.contentTreeController, }); - @override - State createState() => _GroupWidgetState(); -} - -class _GroupWidgetState extends State { @override Widget build(BuildContext context) { - final isExpanded = - widget.contentTreeController.expandedIds.contains(widget.group.id); + return AnimatedBuilder( + animation: contentTreeController, + builder: (context, child) { + final isExpanded = contentTreeController.expandedIds.contains(group.id); - return ExpansionTileWrapper( - ExpansionTile( - key: Key('${widget.group.id}$isExpanded'), - initiallyExpanded: isExpanded, - tilePadding: EdgeInsets.zero, - onExpansionChanged: (expand) { - /// Since expandedIds is also used for expansion, it needs to be - /// updated to prevent the tile to stay collapsed on title tap. - if (!expand) { - widget.contentTreeController.expandedIds.remove(widget.group.id); - setState(() {}); - } - }, - title: GroupTitleWidget( - group: widget.group, - onTap: () { - widget.contentTreeController.openNode(widget.group); - // Couldn't make it rebuild reliably with AnimatedBuilder - setState(() {}); - }, - ), - childrenPadding: const EdgeInsets.only( - left: BeamSizes.size24, - ), - children: [ - GroupNodesWidget( - nodes: widget.group.nodes, - contentTreeController: widget.contentTreeController, + return ExpansionTileWrapper( + ExpansionTile( + key: Key('${group.id}$isExpanded'), + initiallyExpanded: isExpanded, + tilePadding: EdgeInsets.zero, + onExpansionChanged: (isExpanding) { + /// Since expandedIds is also used for expansion, + /// it needs to be updated to prevent the tile from + /// remaining collapsed after taps on title. + if (!isExpanding) { + contentTreeController.markGroupAsCollapsed(group); + } + }, + title: GroupTitleWidget( + group: group, + onTap: () { + contentTreeController.openNode(group); + }, + ), + childrenPadding: const EdgeInsets.only( + left: BeamSizes.size24, + ), + children: [ + GroupNodesWidget( + nodes: group.nodes, + contentTreeController: contentTreeController, + ), + ], ), - ], - ), + ); + }, ); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart index 29ccebd8f3d0..4b316fd26205 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart @@ -24,7 +24,7 @@ import '../../../models/unit.dart'; import '../controllers/content_tree.dart'; import 'tour_progress_indicator.dart'; -class UnitWidget extends StatefulWidget { +class UnitWidget extends StatelessWidget { final UnitModel unit; final ContentTreeController contentTreeController; @@ -33,51 +33,36 @@ class UnitWidget extends StatefulWidget { required this.contentTreeController, }); - @override - State createState() => _UnitWidgetState(); -} - -class _UnitWidgetState extends State { - @override - void initState() { - super.initState(); - widget.contentTreeController.addListener(_rebuild); - } - - @override - void dispose() { - widget.contentTreeController.removeListener(_rebuild); - super.dispose(); - } - - void _rebuild() { - setState(() {}); - } - @override Widget build(BuildContext context) { - final bool isSelected = - widget.contentTreeController.currentNode?.id == widget.unit.id; - return ClickableWidget( - onTap: () => widget.contentTreeController.openNode(widget.unit), - child: Container( - decoration: BoxDecoration( - color: isSelected ? Theme.of(context).selectedRowColor : null, - borderRadius: BorderRadius.circular(BeamSizes.size3), - ), - padding: const EdgeInsets.symmetric(vertical: BeamSizes.size10), - child: Row( - children: [ - TourProgressIndicator( - assetPath: Assets.svg.unitProgress0, - isSelected: isSelected, + return AnimatedBuilder( + animation: contentTreeController, + builder: (context, child) { + final bool isSelected = + contentTreeController.currentNode?.id == unit.id; + + return ClickableWidget( + onTap: () => contentTreeController.openNode(unit), + child: Container( + decoration: BoxDecoration( + color: isSelected ? Theme.of(context).selectedRowColor : null, + borderRadius: BorderRadius.circular(BeamSizes.size3), ), - Expanded( - child: Text(widget.unit.title), + padding: const EdgeInsets.symmetric(vertical: BeamSizes.size10), + child: Row( + children: [ + TourProgressIndicator( + assetPath: Assets.svg.unitProgress0, + isSelected: isSelected, + ), + Expanded( + child: Text(unit.title), + ), + ], ), - ], - ), - ), + ), + ); + }, ); } } From 8807c00d673152762237348aeedd54e9d2aac934 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Sat, 5 Nov 2022 14:20:40 +0300 Subject: [PATCH 03/65] fixed _getNodeAncestors (#23593) --- .../lib/pages/tour/controllers/content_tree.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart index 77d355f13fad..aba409bebc10 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart @@ -73,13 +73,14 @@ class ContentTreeController extends ChangeNotifier { notifyListeners(); } - List _getNodeAncestors(NodeModel node, List ancestors) { + List _getNodeAncestors(NodeModel node, List ancestorIds) { if (node.parent != null) { - ancestors.add(node.parent!.id); - return _getNodeAncestors(node.parent!, ancestors); - } else { - return ancestors.reversed.toList(); + return _getNodeAncestors( + node.parent!, + [...ancestorIds, node.parent!.id], + ); } + return ancestorIds.reversed.toList(); } void _onContentTreeCacheChange() { From 8e8d8c9001b8d238cd45761ced9e9f8afa38f7d9 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Sat, 5 Nov 2022 14:21:03 +0300 Subject: [PATCH 04/65] get sdkId (#23593) --- .../frontend/lib/models/content_tree.dart | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/models/content_tree.dart b/learning/tour-of-beam/frontend/lib/models/content_tree.dart index 14949cc157fa..757953b4ee84 100644 --- a/learning/tour-of-beam/frontend/lib/models/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/models/content_tree.dart @@ -22,25 +22,27 @@ import 'node.dart'; import 'parent_node.dart'; class ContentTreeModel extends ParentNodeModel { - final String sdkId; + final String sdk; final List modules; + String get sdkId => sdk; + @override List get nodes => modules; const ContentTreeModel({ - required this.sdkId, + required this.sdk, required this.modules, }) : super( - id: sdkId, - parent: null, - title: '', - nodes: modules, - ); + id: sdk, + parent: null, + title: '', + nodes: modules, + ); ContentTreeModel.fromResponse(GetContentTreeResponse response) : this( - sdkId: response.sdkId, + sdk: response.sdkId, modules: response.modules .map(ModuleModel.fromResponse) .toList(growable: false), From 2ab4b3bbda36879c8d19c0f1f7ddeaa6ec2234d7 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Wed, 9 Nov 2022 02:49:50 +0600 Subject: [PATCH 05/65] addressing comments (#23593) --- .../pages/tour/controllers/content_tree.dart | 19 +++++++++++++------ .../lib/pages/tour/widgets/group.dart | 10 ++++------ .../tour/widgets/tour_progress_indicator.dart | 10 ++++------ .../frontend/lib/pages/tour/widgets/unit.dart | 3 +-- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart index aba409bebc10..9977cd3c5178 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart @@ -30,14 +30,17 @@ class ContentTreeController extends ChangeNotifier { List _treeIds; NodeModel? _currentNode; final _contentTreeCache = GetIt.instance.get(); - final expandedIds = {}; + final _expandedIds = {}; + + Set get expandedIds => _expandedIds; ContentTreeController({ required String initialSdkId, List initialTreeIds = const [], }) : _sdkId = initialSdkId, _treeIds = initialTreeIds { - expandedIds.addAll(initialTreeIds); + _expandedIds.addAll(initialTreeIds); + _contentTreeCache.addListener(_onContentTreeCacheChange); _onContentTreeCacheChange(); } @@ -48,8 +51,8 @@ class ContentTreeController extends ChangeNotifier { NodeModel? get currentNode => _currentNode; void openNode(NodeModel node) { - if (!expandedIds.contains(node.id)) { - expandedIds.add(node.id); + if (!_expandedIds.contains(node.id)) { + _expandedIds.add(node.id); } if (node == _currentNode) { @@ -68,8 +71,12 @@ class ContentTreeController extends ChangeNotifier { notifyListeners(); } - void markGroupAsCollapsed(GroupModel group) { - expandedIds.remove(group.id); + void updateExpandedIds(GroupModel group, {required bool isExpanding}) { + if (isExpanding) { + _expandedIds.add(group.id); + } else { + _expandedIds.remove(group.id); + } notifyListeners(); } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart index 1ea4374b71f2..64c07538dfcc 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart @@ -47,12 +47,10 @@ class GroupWidget extends StatelessWidget { initiallyExpanded: isExpanded, tilePadding: EdgeInsets.zero, onExpansionChanged: (isExpanding) { - /// Since expandedIds is also used for expansion, - /// it needs to be updated to prevent the tile from - /// remaining collapsed after taps on title. - if (!isExpanding) { - contentTreeController.markGroupAsCollapsed(group); - } + contentTreeController.updateExpandedIds( + group, + isExpanding: isExpanding, + ); }, title: GroupTitleWidget( group: group, diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart index c600317ded31..6f3d6ba56087 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart @@ -32,6 +32,8 @@ class TourProgressIndicator extends StatelessWidget { @override Widget build(BuildContext context) { + final ext = Theme.of(context).extension()!; + return Padding( padding: const EdgeInsets.only( left: BeamSizes.size4, @@ -40,12 +42,8 @@ class TourProgressIndicator extends StatelessWidget { child: SvgPicture.asset( assetPath, color: isSelected - ? Theme.of(context) - .extension()! - .selectedProgressColor - : Theme.of(context) - .extension()! - .unselectedProgressColor, + ? ext.selectedProgressColor + : ext.unselectedProgressColor, ), ); } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart index 4b316fd26205..cfc0e32235a9 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart @@ -38,8 +38,7 @@ class UnitWidget extends StatelessWidget { return AnimatedBuilder( animation: contentTreeController, builder: (context, child) { - final bool isSelected = - contentTreeController.currentNode?.id == unit.id; + final isSelected = contentTreeController.currentNode?.id == unit.id; return ClickableWidget( onTap: () => contentTreeController.openNode(unit), From 57800ee5aa4b775d0fb4bcd2152a855edf724608 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Wed, 9 Nov 2022 10:00:02 +0600 Subject: [PATCH 06/65] sdkId getter & StatelessExpansionTile (#23593) --- .../frontend/lib/models/content_tree.dart | 8 +- .../lib/pages/tour/widgets/group.dart | 75 ++++++++++++------- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/models/content_tree.dart b/learning/tour-of-beam/frontend/lib/models/content_tree.dart index 757953b4ee84..471bb6734fe6 100644 --- a/learning/tour-of-beam/frontend/lib/models/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/models/content_tree.dart @@ -22,19 +22,17 @@ import 'node.dart'; import 'parent_node.dart'; class ContentTreeModel extends ParentNodeModel { - final String sdk; final List modules; - String get sdkId => sdk; + String get sdkId => id; @override List get nodes => modules; const ContentTreeModel({ - required this.sdk, + required super.id, required this.modules, }) : super( - id: sdk, parent: null, title: '', nodes: modules, @@ -42,7 +40,7 @@ class ContentTreeModel extends ParentNodeModel { ContentTreeModel.fromResponse(GetContentTreeResponse response) : this( - sdk: response.sdkId, + id: response.sdkId, modules: response.modules .map(ModuleModel.fromResponse) .toList(growable: false), diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart index 64c07538dfcc..d773ad9b40bb 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart @@ -41,35 +41,56 @@ class GroupWidget extends StatelessWidget { builder: (context, child) { final isExpanded = contentTreeController.expandedIds.contains(group.id); - return ExpansionTileWrapper( - ExpansionTile( - key: Key('${group.id}$isExpanded'), - initiallyExpanded: isExpanded, - tilePadding: EdgeInsets.zero, - onExpansionChanged: (isExpanding) { - contentTreeController.updateExpandedIds( - group, - isExpanding: isExpanding, - ); - }, - title: GroupTitleWidget( - group: group, - onTap: () { - contentTreeController.openNode(group); - }, - ), - childrenPadding: const EdgeInsets.only( - left: BeamSizes.size24, - ), - children: [ - GroupNodesWidget( - nodes: group.nodes, - contentTreeController: contentTreeController, - ), - ], - ), + return _StatelessExpansionTile( + contentTreeController: contentTreeController, + group: group, + isExpanded: isExpanded, ); }, ); } } + +class _StatelessExpansionTile extends StatelessWidget { + final GroupModel group; + final ContentTreeController contentTreeController; + final bool isExpanded; + + const _StatelessExpansionTile({ + required this.group, + required this.contentTreeController, + required this.isExpanded, + }); + + @override + Widget build(BuildContext context) { + return ExpansionTileWrapper( + ExpansionTile( + key: Key('${group.id}$isExpanded'), + initiallyExpanded: isExpanded, + tilePadding: EdgeInsets.zero, + onExpansionChanged: (isExpanding) { + contentTreeController.updateExpandedIds( + group, + isExpanding: isExpanding, + ); + }, + title: GroupTitleWidget( + group: group, + onTap: () { + contentTreeController.openNode(group); + }, + ), + childrenPadding: const EdgeInsets.only( + left: BeamSizes.size24, + ), + children: [ + GroupNodesWidget( + nodes: group.nodes, + contentTreeController: contentTreeController, + ), + ], + ), + ); + } +} From 28cb6b8045409c6fd0915eedb89562c576cbd427 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Wed, 9 Nov 2022 16:09:02 +0600 Subject: [PATCH 07/65] expand & collapse group (#23593) --- .../lib/pages/tour/controllers/content_tree.dart | 13 +++++++------ .../frontend/lib/pages/tour/widgets/group.dart | 9 +++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart index 9977cd3c5178..bfa63c94df4f 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart @@ -71,12 +71,13 @@ class ContentTreeController extends ChangeNotifier { notifyListeners(); } - void updateExpandedIds(GroupModel group, {required bool isExpanding}) { - if (isExpanding) { - _expandedIds.add(group.id); - } else { - _expandedIds.remove(group.id); - } + void expandGroup(GroupModel group) { + _expandedIds.add(group.id); + notifyListeners(); + } + + void collapseGroup(GroupModel group) { + _expandedIds.remove(group.id); notifyListeners(); } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart index d773ad9b40bb..67c3f9528599 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart @@ -70,10 +70,11 @@ class _StatelessExpansionTile extends StatelessWidget { initiallyExpanded: isExpanded, tilePadding: EdgeInsets.zero, onExpansionChanged: (isExpanding) { - contentTreeController.updateExpandedIds( - group, - isExpanding: isExpanding, - ); + if (isExpanding) { + contentTreeController.expandGroup(group); + } else { + contentTreeController.collapseGroup(group); + } }, title: GroupTitleWidget( group: group, From 85e12348b44d1422414cdc74bb46623602ebda1c Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Wed, 9 Nov 2022 19:55:01 +0600 Subject: [PATCH 08/65] StatelessExpansionTile (#23593) --- .../lib/pages/tour/widgets/group.dart | 66 +++++-------------- .../widgets/stateless_expansion_tile.dart | 37 +++++++++++ 2 files changed, 55 insertions(+), 48 deletions(-) create mode 100644 learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart index 67c3f9528599..3af250d57ee9 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart @@ -17,13 +17,12 @@ */ import 'package:flutter/material.dart'; -import 'package:playground_components/playground_components.dart'; -import '../../../components/expansion_tile_wrapper.dart'; import '../../../models/group.dart'; import '../controllers/content_tree.dart'; import 'group_nodes.dart'; import 'group_title.dart'; +import 'stateless_expansion_tile.dart'; class GroupWidget extends StatelessWidget { final GroupModel group; @@ -41,57 +40,28 @@ class GroupWidget extends StatelessWidget { builder: (context, child) { final isExpanded = contentTreeController.expandedIds.contains(group.id); - return _StatelessExpansionTile( - contentTreeController: contentTreeController, - group: group, + return StatelessExpansionTile( + key: Key('${group.id}$isExpanded'), isExpanded: isExpanded, - ); - }, - ); - } -} - -class _StatelessExpansionTile extends StatelessWidget { - final GroupModel group; - final ContentTreeController contentTreeController; - final bool isExpanded; - - const _StatelessExpansionTile({ - required this.group, - required this.contentTreeController, - required this.isExpanded, - }); - - @override - Widget build(BuildContext context) { - return ExpansionTileWrapper( - ExpansionTile( - key: Key('${group.id}$isExpanded'), - initiallyExpanded: isExpanded, - tilePadding: EdgeInsets.zero, - onExpansionChanged: (isExpanding) { - if (isExpanding) { - contentTreeController.expandGroup(group); - } else { - contentTreeController.collapseGroup(group); - } - }, - title: GroupTitleWidget( - group: group, - onTap: () { - contentTreeController.openNode(group); + onExpansionChanged: (isExpanding) { + if (isExpanding) { + contentTreeController.expandGroup(group); + } else { + contentTreeController.collapseGroup(group); + } }, - ), - childrenPadding: const EdgeInsets.only( - left: BeamSizes.size24, - ), - children: [ - GroupNodesWidget( + title: GroupTitleWidget( + group: group, + onTap: () { + contentTreeController.openNode(group); + }, + ), + child: GroupNodesWidget( nodes: group.nodes, contentTreeController: contentTreeController, ), - ], - ), + ); + }, ); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart new file mode 100644 index 000000000000..84a563328187 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:playground_components/playground_components.dart'; + +import '../../../components/expansion_tile_wrapper.dart'; + +class StatelessExpansionTile extends StatelessWidget { + final bool isExpanded; + final void Function(bool)? onExpansionChanged; + final Widget title; + final Widget child; + + const StatelessExpansionTile({ + required super.key, + required this.isExpanded, + required this.onExpansionChanged, + required this.title, + required this.child, + }); + + @override + Widget build(BuildContext context) { + return ExpansionTileWrapper( + ExpansionTile( + // TODO(nausharipov): isn't rebuilt without key. + key: key, + initiallyExpanded: isExpanded, + tilePadding: EdgeInsets.zero, + onExpansionChanged: onExpansionChanged, + title: title, + childrenPadding: const EdgeInsets.only( + left: BeamSizes.size24, + ), + children: [child], + ), + ); + } +} From 8dc77197d63552a6664643842017f38a9ae57e66 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 10 Nov 2022 14:07:00 +0600 Subject: [PATCH 09/65] license (#23593) --- .../tour/widgets/stateless_expansion_tile.dart | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart index 84a563328187..aa39b9abd249 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart @@ -1,3 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; From e4dee7bad46970ceda1fbb448fe527b8a566237f Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 11 Nov 2022 12:15:20 +0600 Subject: [PATCH 10/65] ValueChanged and ValueKey in StatelessExpansionTile (#23593) --- .../tour-of-beam/frontend/lib/pages/tour/widgets/group.dart | 1 - .../lib/pages/tour/widgets/stateless_expansion_tile.dart | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart index 3af250d57ee9..fad732b105bb 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group.dart @@ -41,7 +41,6 @@ class GroupWidget extends StatelessWidget { final isExpanded = contentTreeController.expandedIds.contains(group.id); return StatelessExpansionTile( - key: Key('${group.id}$isExpanded'), isExpanded: isExpanded, onExpansionChanged: (isExpanding) { if (isExpanding) { diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart index aa39b9abd249..149bd04a586e 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart @@ -23,12 +23,11 @@ import '../../../components/expansion_tile_wrapper.dart'; class StatelessExpansionTile extends StatelessWidget { final bool isExpanded; - final void Function(bool)? onExpansionChanged; + final ValueChanged? onExpansionChanged; final Widget title; final Widget child; const StatelessExpansionTile({ - required super.key, required this.isExpanded, required this.onExpansionChanged, required this.title, @@ -39,8 +38,7 @@ class StatelessExpansionTile extends StatelessWidget { Widget build(BuildContext context) { return ExpansionTileWrapper( ExpansionTile( - // TODO(nausharipov): isn't rebuilt without key. - key: key, + key: ValueKey(isExpanded), initiallyExpanded: isExpanded, tilePadding: EdgeInsets.zero, onExpansionChanged: onExpansionChanged, From 5b07e91391383a7f6c6d40379a1787a8f3003da7 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 14 Nov 2022 18:49:34 +0600 Subject: [PATCH 11/65] optional SDK selector in tour scaffold --- .../frontend/lib/components/scaffold.dart | 17 +++++++------- .../frontend/lib/components/sdk_dropdown.dart | 19 +++++++++------- .../pages/tour/controllers/content_tree.dart | 5 +++++ .../frontend/lib/pages/tour/screen.dart | 22 +++++++++++++++++++ .../frontend/lib/pages/tour/state.dart | 6 +++++ .../frontend/lib/pages/welcome/screen.dart | 1 + 6 files changed, 54 insertions(+), 16 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/components/scaffold.dart b/learning/tour-of-beam/frontend/lib/components/scaffold.dart index f8352140436e..738fc7207140 100644 --- a/learning/tour-of-beam/frontend/lib/components/scaffold.dart +++ b/learning/tour-of-beam/frontend/lib/components/scaffold.dart @@ -23,14 +23,15 @@ import 'footer.dart'; import 'login/login_button.dart'; import 'logo.dart'; import 'profile/avatar.dart'; -import 'sdk_dropdown.dart'; class TobScaffold extends StatelessWidget { final Widget child; + final Widget? sdkSelector; const TobScaffold({ super.key, required this.child, + required this.sdkSelector, }); // TODO(nausharipov): get state @@ -41,15 +42,15 @@ class TobScaffold extends StatelessWidget { return Scaffold( appBar: AppBar( title: const Logo(), - actions: const [ - _ActionVerticalPadding(child: SdkDropdown()), - SizedBox(width: BeamSizes.size12), - _ActionVerticalPadding(child: ToggleThemeButton()), - SizedBox(width: BeamSizes.size6), - _ActionVerticalPadding( + actions: [ + if (sdkSelector != null) _ActionVerticalPadding(child: sdkSelector!), + const SizedBox(width: BeamSizes.size12), + const _ActionVerticalPadding(child: ToggleThemeButton()), + const SizedBox(width: BeamSizes.size6), + const _ActionVerticalPadding( child: _isAuthorized ? Avatar() : LoginButton(), ), - SizedBox(width: BeamSizes.size16), + const SizedBox(width: BeamSizes.size16), ], ), body: Column( diff --git a/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart index 689860b8466c..dd65f020da20 100644 --- a/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart +++ b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart @@ -22,7 +22,12 @@ import 'package:playground_components/playground_components.dart'; import 'builders/sdks.dart'; class SdkDropdown extends StatelessWidget { - const SdkDropdown(); + final String sdkId; + final void Function(String? sdkId) onChanged; + const SdkDropdown({ + required this.sdkId, + required this.onChanged, + }); @override Widget build(BuildContext context) { @@ -34,10 +39,8 @@ class SdkDropdown extends StatelessWidget { return _DropdownWrapper( child: DropdownButton( - value: sdks.first.id, - onChanged: (sdk) { - // TODO(nausharipov): change SDK - }, + value: sdkId, + onChanged: onChanged, items: sdks .map( (sdk) => DropdownMenuItem( @@ -46,7 +49,6 @@ class SdkDropdown extends StatelessWidget { ), ) .toList(growable: false), - isDense: true, alignment: Alignment.center, focusColor: BeamColors.transparent, borderRadius: BorderRadius.circular(BeamSizes.size6), @@ -63,9 +65,10 @@ class _DropdownWrapper extends StatelessWidget { @override Widget build(BuildContext context) { - return DecoratedBox( + return Container( + padding: const EdgeInsets.only(left: BeamSizes.size10), decoration: BoxDecoration( - color: Theme.of(context).hoverColor, + color: Theme.of(context).selectedRowColor, borderRadius: BorderRadius.circular(BeamSizes.size6), ), child: DropdownButtonHideUnderline(child: child), diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart index bfa63c94df4f..5cf1778171e5 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart @@ -47,6 +47,11 @@ class ContentTreeController extends ChangeNotifier { Sdk get sdk => Sdk.parseOrCreate(_sdkId); String get sdkId => _sdkId; + set sdkId(String newValue) { + _sdkId = newValue; + notifyListeners(); + } + List get treeIds => _treeIds; NodeModel? get currentNode => _currentNode; diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart index 3557111c0f76..95cc71a1d3b0 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart @@ -20,6 +20,7 @@ import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; import '../../components/scaffold.dart'; +import '../../components/sdk_dropdown.dart'; import '../../constants/sizes.dart'; import 'state.dart'; import 'widgets/content.dart'; @@ -34,6 +35,7 @@ class TourScreen extends StatelessWidget { @override Widget build(BuildContext context) { return TobScaffold( + sdkSelector: _SdkSelector(notifier: notifier), child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns ? _WideTour(notifier) : _NarrowTour(notifier), @@ -106,3 +108,23 @@ class _NarrowScreenPlayground extends StatelessWidget { return const Center(child: Text('TODO: Playground for narrow screen')); } } + +class _SdkSelector extends StatelessWidget { + final TourNotifier notifier; + const _SdkSelector({required this.notifier}); + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: notifier, + builder: (context, child) => SdkDropdown( + sdkId: notifier.sdk.id, + onChanged: (sdkId) { + if (sdkId != null) { + notifier.sdk = Sdk.parseOrCreate(sdkId); + } + }, + ), + ); + } +} diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index e709839e915e..82937b348dd6 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -53,6 +53,12 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { treeIds: contentTreeController.treeIds, ); + Sdk get sdk => contentTreeController.sdk; + set sdk(Sdk sdk) { + playgroundController.setSdk(sdk); + contentTreeController.sdkId = sdk.id; + } + void _onChanged() { emitPathChanged(); final currentNode = contentTreeController.currentNode; diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart index af6e91969bd2..4c6901791c96 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart @@ -38,6 +38,7 @@ class WelcomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return TobScaffold( + sdkSelector: null, child: SingleChildScrollView( child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns ? _WideWelcome(notifier) From 497ff7cf40af947a29e1ebf81163ef315ca4ecfb Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 14 Nov 2022 23:29:45 +0600 Subject: [PATCH 12/65] AppNotifier --- .../frontend/lib/components/scaffold.dart | 30 ++++++++++-- .../tour-of-beam/frontend/lib/locator.dart | 2 + .../frontend/lib/pages/tour/screen.dart | 23 +-------- .../frontend/lib/pages/tour/state.dart | 10 ++-- .../frontend/lib/pages/welcome/screen.dart | 49 ++++++++++++------- .../frontend/lib/pages/welcome/state.dart | 24 +-------- learning/tour-of-beam/frontend/lib/state.dart | 34 +++++++++++++ learning/tour-of-beam/frontend/pubspec.lock | 42 ++++++++++++++++ learning/tour-of-beam/frontend/pubspec.yaml | 1 + 9 files changed, 144 insertions(+), 71 deletions(-) create mode 100644 learning/tour-of-beam/frontend/lib/state.dart diff --git a/learning/tour-of-beam/frontend/lib/components/scaffold.dart b/learning/tour-of-beam/frontend/lib/components/scaffold.dart index 738fc7207140..f58bf60c17bf 100644 --- a/learning/tour-of-beam/frontend/lib/components/scaffold.dart +++ b/learning/tour-of-beam/frontend/lib/components/scaffold.dart @@ -17,21 +17,24 @@ */ import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; +import '../state.dart'; import 'footer.dart'; import 'login/login_button.dart'; import 'logo.dart'; import 'profile/avatar.dart'; +import 'sdk_dropdown.dart'; class TobScaffold extends StatelessWidget { final Widget child; - final Widget? sdkSelector; + final bool showSdkSelector; const TobScaffold({ super.key, required this.child, - required this.sdkSelector, + required this.showSdkSelector, }); // TODO(nausharipov): get state @@ -43,7 +46,8 @@ class TobScaffold extends StatelessWidget { appBar: AppBar( title: const Logo(), actions: [ - if (sdkSelector != null) _ActionVerticalPadding(child: sdkSelector!), + if (showSdkSelector) + const _ActionVerticalPadding(child: _SdkSelector()), const SizedBox(width: BeamSizes.size12), const _ActionVerticalPadding(child: ToggleThemeButton()), const SizedBox(width: BeamSizes.size6), @@ -76,3 +80,23 @@ class _ActionVerticalPadding extends StatelessWidget { ); } } + +class _SdkSelector extends StatelessWidget { + const _SdkSelector(); + + @override + Widget build(BuildContext context) { + final notifier = GetIt.instance.get(); + return AnimatedBuilder( + animation: notifier, + builder: (context, child) => notifier.sdkId == null + ? Container() + : SdkDropdown( + sdkId: notifier.sdkId!, + onChanged: (sdkId) { + notifier.sdkId = sdkId; + }, + ), + ); + } +} diff --git a/learning/tour-of-beam/frontend/lib/locator.dart b/learning/tour-of-beam/frontend/lib/locator.dart index f8146a212e24..74e027d13dc7 100644 --- a/learning/tour-of-beam/frontend/lib/locator.dart +++ b/learning/tour-of-beam/frontend/lib/locator.dart @@ -26,6 +26,7 @@ import 'pages/welcome/page.dart'; import 'repositories/client/cloud_functions_client.dart'; import 'router/page_factory.dart'; import 'router/route_information_parser.dart'; +import 'state.dart'; Future initializeServiceLocator() async { _initializeCaches(); @@ -35,6 +36,7 @@ Future initializeServiceLocator() async { void _initializeCaches() { final client = CloudFunctionsTobClient(); + GetIt.instance.registerSingleton(AppNotifier()); GetIt.instance.registerSingleton(ContentTreeCache(client: client)); GetIt.instance.registerSingleton(SdkCache(client: client)); GetIt.instance.registerSingleton(UnitContentCache(client: client)); diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart index 95cc71a1d3b0..6ba9ba2e1185 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart @@ -20,7 +20,6 @@ import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; import '../../components/scaffold.dart'; -import '../../components/sdk_dropdown.dart'; import '../../constants/sizes.dart'; import 'state.dart'; import 'widgets/content.dart'; @@ -35,7 +34,7 @@ class TourScreen extends StatelessWidget { @override Widget build(BuildContext context) { return TobScaffold( - sdkSelector: _SdkSelector(notifier: notifier), + showSdkSelector: true, child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns ? _WideTour(notifier) : _NarrowTour(notifier), @@ -108,23 +107,3 @@ class _NarrowScreenPlayground extends StatelessWidget { return const Center(child: Text('TODO: Playground for narrow screen')); } } - -class _SdkSelector extends StatelessWidget { - final TourNotifier notifier; - const _SdkSelector({required this.notifier}); - - @override - Widget build(BuildContext context) { - return AnimatedBuilder( - animation: notifier, - builder: (context, child) => SdkDropdown( - sdkId: notifier.sdk.id, - onChanged: (sdkId) { - if (sdkId != null) { - notifier.sdk = Sdk.parseOrCreate(sdkId); - } - }, - ), - ); - } -} diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 82937b348dd6..0607d1a672c3 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -25,12 +25,14 @@ import '../../cache/unit_content.dart'; import '../../config.dart'; import '../../models/unit.dart'; import '../../models/unit_content.dart'; +import '../../state.dart'; import 'controllers/content_tree.dart'; import 'path.dart'; class TourNotifier extends ChangeNotifier with PageStateMixin { final ContentTreeController contentTreeController; final PlaygroundController playgroundController; + final _appNotifier = GetIt.instance.get(); final _unitContentCache = GetIt.instance.get(); UnitContentModel? _currentUnitContent; @@ -44,6 +46,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { playgroundController = _createPlaygroundController(initialSdkId) { contentTreeController.addListener(_onChanged); _unitContentCache.addListener(_onChanged); + _appNotifier.addListener(_setSdk); _onChanged(); } @@ -53,10 +56,9 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { treeIds: contentTreeController.treeIds, ); - Sdk get sdk => contentTreeController.sdk; - set sdk(Sdk sdk) { - playgroundController.setSdk(sdk); - contentTreeController.sdkId = sdk.id; + void _setSdk() { + playgroundController.setSdk(Sdk.parseOrCreate(_appNotifier.sdkId!)); + contentTreeController.sdkId = _appNotifier.sdkId!; } void _onChanged() { diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart index 4c6901791c96..0adf9a0f49f3 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart @@ -16,10 +16,12 @@ * limitations under the License. */ +import 'package:app_state/app_state.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; import '../../components/builders/content_tree.dart'; @@ -28,6 +30,8 @@ import '../../components/scaffold.dart'; import '../../constants/sizes.dart'; import '../../generated/assets.gen.dart'; import '../../models/module.dart'; +import '../../state.dart'; +import '../tour/page.dart'; import 'state.dart'; class WelcomeScreen extends StatelessWidget { @@ -38,7 +42,7 @@ class WelcomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return TobScaffold( - sdkSelector: null, + showSdkSelector: false, child: SingleChildScrollView( child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns ? _WideWelcome(notifier) @@ -58,12 +62,12 @@ class _WideWelcome extends StatelessWidget { return IntrinsicHeight( child: Row( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: const [ Expanded( - child: _SdkSelection(notifier), + child: _SdkSelection(), ), Expanded( - child: _TourSummary(notifier), + child: _TourSummary(), ), ], ), @@ -79,23 +83,22 @@ class _NarrowWelcome extends StatelessWidget { @override Widget build(BuildContext context) { return Column( - children: [ - _SdkSelection(notifier), - _TourSummary(notifier), + children: const [ + _SdkSelection(), + _TourSummary(), ], ); } } class _SdkSelection extends StatelessWidget { - final WelcomeNotifier notifier; - - const _SdkSelection(this.notifier); + const _SdkSelection(); static const double _minimalHeight = 900; @override Widget build(BuildContext context) { + final appNotifier = GetIt.instance.get(); return Container( constraints: BoxConstraints( minHeight: MediaQuery.of(context).size.height - @@ -128,12 +131,14 @@ class _SdkSelection extends StatelessWidget { } return AnimatedBuilder( - animation: notifier, + animation: appNotifier, builder: (context, child) => _Buttons( sdks: sdks, - sdkId: notifier.sdkId, - setSdkId: (v) => notifier.sdkId = v, - onStartPressed: notifier.startTour, + sdkId: appNotifier.sdkId, + setSdkId: (v) => appNotifier.sdkId = v, + onStartPressed: () { + startTour(appNotifier.sdkId); + }, ), ); }, @@ -145,19 +150,25 @@ class _SdkSelection extends StatelessWidget { ), ); } + + void startTour(String? sdkId) { + if (sdkId == null) { + return; + } + GetIt.instance.get().push(TourPage(sdkId: sdkId)); + } } class _TourSummary extends StatelessWidget { - final WelcomeNotifier notifier; - - const _TourSummary(this.notifier); + const _TourSummary(); @override Widget build(BuildContext context) { + final appNotifier = GetIt.instance.get(); return AnimatedBuilder( - animation: notifier, + animation: appNotifier, builder: (context, child) { - final sdkId = notifier.sdkId; + final sdkId = appNotifier.sdkId; if (sdkId == null) { return Container(); } diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/state.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/state.dart index d95b288a61be..0b381a995743 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/state.dart @@ -18,32 +18,10 @@ import 'package:app_state/app_state.dart'; import 'package:flutter/widgets.dart'; -import 'package:get_it/get_it.dart'; - -import '../tour/page.dart'; import 'path.dart'; class WelcomeNotifier extends ChangeNotifier with PageStateMixin { - String? _sdkId; - + // TODO(nausharipov): remove state from Welcome? @override PagePath get path => const WelcomePath(); - - String? get sdkId => _sdkId; - - set sdkId(String? newValue) { - _sdkId = newValue; - notifyListeners(); - } - - void startTour() { - final sdkId = _sdkId; - if (sdkId == null) { - return; - } - - GetIt.instance.get().push( - TourPage(sdkId: sdkId), - ); - } } diff --git a/learning/tour-of-beam/frontend/lib/state.dart b/learning/tour-of-beam/frontend/lib/state.dart new file mode 100644 index 000000000000..400375e149e9 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/state.dart @@ -0,0 +1,34 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +class AppNotifier extends ChangeNotifier { + static const _storage = FlutterSecureStorage(); + static const _sdkIdStorageKey = 'sdkId'; + String? _sdkId; + + AppNotifier() { + unawaited(_readSdkId()); + } + + String? get sdkId => _sdkId; + + set sdkId(String? newValue) { + _sdkId = newValue; + unawaited(_writeSdkId()); + notifyListeners(); + } + + Future _writeSdkId() async { + await _storage.write( + key: _sdkIdStorageKey, + value: _sdkId, + ); + } + + Future _readSdkId() async { + _sdkId = await _storage.read(key: _sdkIdStorageKey); + notifyListeners(); + } +} diff --git a/learning/tour-of-beam/frontend/pubspec.lock b/learning/tour-of-beam/frontend/pubspec.lock index 6b49ce6e37bc..9fd4f59c25c5 100644 --- a/learning/tour-of-beam/frontend/pubspec.lock +++ b/learning/tour-of-beam/frontend/pubspec.lock @@ -324,6 +324,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.12" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.0" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.2" flutter_svg: dependency: "direct main" description: diff --git a/learning/tour-of-beam/frontend/pubspec.yaml b/learning/tour-of-beam/frontend/pubspec.yaml index a8f4fd9a4ce7..86cc96ce4754 100644 --- a/learning/tour-of-beam/frontend/pubspec.yaml +++ b/learning/tour-of-beam/frontend/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: easy_localization_loader: ^1.0.0 flutter: { sdk: flutter } flutter_markdown: ^0.6.12 + flutter_secure_storage: ^6.0.0 flutter_svg: ^1.0.3 get_it: ^7.2.0 google_fonts: ^3.0.1 From 83c9c0e80288b0e2e34044285b3e626462ea9e9d Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 15 Nov 2022 10:44:51 +0600 Subject: [PATCH 13/65] moved AppNotifier into _initializeState --- learning/tour-of-beam/frontend/lib/locator.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/learning/tour-of-beam/frontend/lib/locator.dart b/learning/tour-of-beam/frontend/lib/locator.dart index 74e027d13dc7..84d737421d50 100644 --- a/learning/tour-of-beam/frontend/lib/locator.dart +++ b/learning/tour-of-beam/frontend/lib/locator.dart @@ -36,13 +36,13 @@ Future initializeServiceLocator() async { void _initializeCaches() { final client = CloudFunctionsTobClient(); - GetIt.instance.registerSingleton(AppNotifier()); GetIt.instance.registerSingleton(ContentTreeCache(client: client)); GetIt.instance.registerSingleton(SdkCache(client: client)); GetIt.instance.registerSingleton(UnitContentCache(client: client)); } void _initializeState() { + GetIt.instance.registerSingleton(AppNotifier()); GetIt.instance.registerSingleton( PageStack( bottomPage: WelcomePage(), From 9d1f49bb44e6dd4e24254b750fef751e8d554f23 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 15 Nov 2022 15:29:06 +0600 Subject: [PATCH 14/65] StorageKeys --- .../frontend/lib/constants/storage_keys.dart | 21 ++++++++++++++++ .../frontend/lib/pages/tour/state.dart | 7 ++++-- learning/tour-of-beam/frontend/lib/state.dart | 25 ++++++++++++++++--- 3 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 learning/tour-of-beam/frontend/lib/constants/storage_keys.dart diff --git a/learning/tour-of-beam/frontend/lib/constants/storage_keys.dart b/learning/tour-of-beam/frontend/lib/constants/storage_keys.dart new file mode 100644 index 000000000000..84b289e115e8 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/constants/storage_keys.dart @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class StorageKeys { + static const sdkId = 'sdkId'; +} diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 0607d1a672c3..b7351720127f 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -57,8 +57,11 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { ); void _setSdk() { - playgroundController.setSdk(Sdk.parseOrCreate(_appNotifier.sdkId!)); - contentTreeController.sdkId = _appNotifier.sdkId!; + final sdkId = _appNotifier.sdkId; + if (sdkId != null) { + playgroundController.setSdk(Sdk.parseOrCreate(sdkId)); + contentTreeController.sdkId = sdkId; + } } void _onChanged() { diff --git a/learning/tour-of-beam/frontend/lib/state.dart b/learning/tour-of-beam/frontend/lib/state.dart index 400375e149e9..250ebc0c2558 100644 --- a/learning/tour-of-beam/frontend/lib/state.dart +++ b/learning/tour-of-beam/frontend/lib/state.dart @@ -1,11 +1,30 @@ +/* + * 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:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'constants/storage_keys.dart'; + class AppNotifier extends ChangeNotifier { static const _storage = FlutterSecureStorage(); - static const _sdkIdStorageKey = 'sdkId'; String? _sdkId; AppNotifier() { @@ -22,13 +41,13 @@ class AppNotifier extends ChangeNotifier { Future _writeSdkId() async { await _storage.write( - key: _sdkIdStorageKey, + key: StorageKeys.sdkId, value: _sdkId, ); } Future _readSdkId() async { - _sdkId = await _storage.read(key: _sdkIdStorageKey); + _sdkId = await _storage.read(key: StorageKeys.sdkId); notifyListeners(); } } From b78bbd33dc518c57d92c3261e020ab12b7ea9d33 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Wed, 16 Nov 2022 14:46:07 +0600 Subject: [PATCH 15/65] remove listener --- learning/tour-of-beam/frontend/lib/pages/tour/state.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index b7351720127f..8184a19df9f5 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -163,6 +163,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { void dispose() { _unitContentCache.removeListener(_onChanged); contentTreeController.removeListener(_onChanged); + _appNotifier.removeListener(_setSdk); super.dispose(); } } From 5297d2548ced6027c58b75b9d917fbfeb7052369 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Wed, 19 Oct 2022 19:50:43 +0600 Subject: [PATCH 16/65] auth, complete unit, user progress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AuthNotifier draft (#23692) Comments (#23692) Comments (#23692)(1) sign in with google works (#23692) new configs (#23692) get user progress draft (#23692) comment fixes (#23692) sign in in IntroTextBody (#23692) reverted config (#23692) comment fixes (#23692) WIP before rebase (merge) (#23692) Squashed commit of the following: commit bff4919ff00ec3b5d7186efde41c884dfc4c8344 Merge: 79ba69483a ce8d618c77 Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Thu Nov 17 10:34:02 2022 +0100 Merge pull request #24186: Uses _all to follow alias/datastreams when estimating index size commit 79ba69483a84ea0278d0b0ddb141200739607c77 Merge: 245fea9040 b7e860a762 Author: Chamikara Jayalath Date: Wed Nov 16 20:47:40 2022 -0800 Merge pull request #24218: Update Python wheel format for RC validation commit 245fea904014cd58d4148807463dbaa40000774c Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed Nov 16 18:12:33 2022 -0800 Bump loader-utils from 1.4.1 to 1.4.2 in /sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel (#24191) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit e1de8e78deeb5d17617fda6591429eaaf8abb8a2 Author: Yi Hu Date: Wed Nov 16 20:48:06 2022 -0500 Fix PythonLint (#24219) commit b7e860a7621771c300dcec625655f87e62591323 Author: Chamikara Jayalath Date: Wed Nov 16 17:28:31 2022 -0800 updates commit c2feb09ea49dd815b69c65e531ce34128756d988 Author: Chamikara Jayalath Date: Wed Nov 16 17:06:08 2022 -0800 updates commit ce8d618c77d23e20a1ddb128bb8183048597d096 Author: egalpin Date: Wed Nov 16 16:43:57 2022 -0800 Adds test for following aliases when estimating index size commit 959719d01c627328c0ca2849d2b7e2c9b322d4d1 Author: Chamikara Jayalath Date: Wed Nov 16 15:16:06 2022 -0800 Temporary update Python RC validation job commit b952b41788acc20edbe5b75b2196f30dbf8fdeb0 Author: Yi Hu Date: Wed Nov 16 14:18:12 2022 -0500 Python TextIO Performance Test (#23951) * Python TextIO Performance Test * Add filebasedio_perf_test module for unified test framework for Python file-based IOs * Fix MetricsReader publishes metrics duplicately if more than one load test declared. This is because MetricsReader.publishers was static class variable * Fix pylint * Distribute Python performance tests random time at a day instead of all at 3PM * Add information about length conversion commit 017f2cbde124af40a43be99ec88289fcf63c1c95 Merge: fef8acdbc0 88dba4f494 Author: Chamikara Jayalath Date: Wed Nov 16 10:39:52 2022 -0800 Merge pull request #24187: Add a reference to Java RunInference example commit fef8acdbc0ecbcc85b49144adaf8830e3bc6b2de Merge: 6e9187e67e ead245539d Author: Ahmet Altay Date: Wed Nov 16 10:24:53 2022 -0800 Merge pull request #24199 from Laksh47/issue#24196 refs: issue-24196, fix broken hyperlink commit 6e9187e67e1bd8f73997f437f0ed4c29880ed73b Author: Darkhan Nausharipov <31556582+nausharipov@users.noreply.github.com> Date: Wed Nov 16 22:33:50 2022 +0600 [Tour of Beam] [Frontend] Content tree URLs (#23776) * Content tree navigation (#23593) Unit content navigation (#23593) Update URL on node click (#23593) Active unit color (#23593) removeListener in unit (#23593) First unit is opened on group title click (#23593) WIP by Alexey Inkin (#23593) selectedUnitColor (#23593) Unit borderRadius (#23593) RegExp todo (#23593) added referenced collection package to remove warning (#23593) small refinement (#23593) expand on group tap, padding, openNode (#23593) group expansion bug fix (#23593) selected & unselected progress indicators (#23593) * AnimatedBuilders instead of StatefulWidgets in unit & group (#23593) * fixed _getNodeAncestors (#23593) * get sdkId (#23593) * addressing comments (#23593) * sdkId getter & StatelessExpansionTile (#23593) * expand & collapse group (#23593) * StatelessExpansionTile (#23593) * license (#23593) * ValueChanged and ValueKey in StatelessExpansionTile (#23593) Co-authored-by: darkhan.nausharipov Co-authored-by: Alexey Inkin commit b33fac2aa533d77cfa47f88466c8cd6bd3f3e864 Author: Bruno Volpato Date: Wed Nov 16 10:51:11 2022 -0500 Use only ValueProviders in SpannerConfig (#24156) commit 5f013ab6567ec75b460b2081d7f89d332320caff Author: Robert Burke Date: Wed Nov 16 07:23:10 2022 -0800 revert upgrade to go 1.19 for action unit tests (#24189) commit 9337f4dbecc929886f8559949a082a649fd9d1bb Author: Yi Hu Date: Wed Nov 16 10:18:42 2022 -0500 Fix Python PostCommit Example CustomPTransformIT on portable (#24159) * Fix Python PostCommit Examples on portable * Fix custom_ptransform pipeline options gets modified * Specify flinkConfDir commit ead245539d01dec0f3e08699c1e1cc6777a5ef0e Author: Laksh Date: Wed Nov 16 09:32:46 2022 -0500 refs: issue-24196, fix broken hyperlink commit e83a996d4374d467d95bcfad7166905622ec615c Merge: 2fc56ec663 ffdee0b6ed Author: Jan Lukavský Date: Wed Nov 16 15:15:31 2022 +0100 Merge pull request #24192: Re-use serializable pipeline options when already available. commit ffdee0b6edb8638c78a65ec85c727ea5dde1cb2f Author: Jozef Vilcek Date: Mon Nov 14 16:48:18 2022 +0100 Re-use serializable pipeline options when already available (#24192) commit 88dba4f494829b2b3530b767fb8c5252e0d2ba44 Author: Chamikara Jayalath Date: Tue Nov 15 16:21:22 2022 -0800 Add a reference to Java RunInference example commit 2fc56ec663e335cfcf37dc57d471f79b601414f4 Merge: f763186987 83f1bc19b9 Author: Kenn Knowles Date: Tue Nov 15 16:16:47 2022 -0800 Merge pull request #24142: Fix arguments to checkState in BatchViewOverrides commit f763186987c00ba1d26efdc35406436a1fa69a9a Merge: c2bc2135e9 0d7ca04182 Author: Ning Kang Date: Tue Nov 15 15:25:20 2022 -0800 Addresses #24161 Updated README of Interactive Beam commit c2bc2135e9bce715990a5d5551e2bc2dc0311da4 Author: Doug Judd Date: Tue Nov 15 14:48:26 2022 -0800 Strip FGAC database role from changestreams metadata requests (#24177) Co-authored-by: Doug Judd commit af637974f96ad1b5110d7dea3f9a26c68e19a51b Author: Jack McCluskey <34928439+jrmccluskey@users.noreply.github.com> Date: Tue Nov 15 17:16:43 2022 -0500 Add custom inference function support to the PyTorch model handler (#24062) * Initial type def and function signature * [Draft] Add custom inference fn support to Pytorch Model Handler * Formatting * Split out default * Remove Keyed version for testing * Move device optimization * Make default available for import, add to test classes * Remove incorrect default from keyed test * Keyed impl * Fix device arg * custom inference test * formatting * Add helpers to define custom inference functions using model methods * Trailing whitespace * Unit tests * Fix incorrect getattr syntax * Type typo * Fix docstring * Fix keyed helper, add basic generate route * Modify generate() to be different than forward() * formatting * Remove extra generate() def commit a014637106970a0a0e9eb7944aa5caf79fa5fd37 Author: egalpin Date: Tue Nov 15 13:57:54 2022 -0800 Uses _all to follow alias/datastreams when estimating index size Fixes #24117 commit 0d7ca041823bc2b09f76f86fdfd1d0b9508c9c88 Author: Ning Kang Date: Tue Nov 15 13:57:27 2022 -0800 Minor update commit e8fc759d756f4a987e41d2b9da56b906a6cd7736 Author: Ning Kang Date: Tue Nov 15 13:52:18 2022 -0800 Updated README of Interactive Beam Removed deprecated cache_dir runner param in favor of the cache_root global option. commit 08d5f72e5f35d41f3e9fa9fe799caea6bed1b7a7 Author: Anand Inguva <34158215+AnandInguva@users.noreply.github.com> Date: Tue Nov 15 16:34:21 2022 -0500 [Python]Support pipe operator as Union (PEP -604) (#24106) Fixes https://github.com/apache/beam/issues/21972 commit 526e7a58b62682582c27173ab21ed8667ddab766 Author: Scott Strong Date: Tue Nov 15 16:26:45 2022 -0500 Using Teardown context instead of deprecated finalize (#24180) * Using Teardown context instead of deprecated finalize * making function public Co-authored-by: Scott Strong commit fb4d1d4dea7b26ed538a9f6aca0ed41e8c300e37 Author: Danny McCormick Date: Tue Nov 15 16:25:22 2022 -0500 Fix broken json for notebook (#24183) commit f98db2008a97f4546d036ddf0dddfee8c87eb58a Author: Robert Burke Date: Tue Nov 15 12:49:23 2022 -0800 Update automation to use Go 1.19 (#24175) Co-authored-by: lostluck <13907733+lostluck@users.noreply.github.com> commit e5f58504eef1fdeebe0402cda8a2df259169c704 Author: Brian Hulette Date: Tue Nov 15 12:25:13 2022 -0800 Add error reporting for BatchConverter match failure (#24022) * add error reporting for BatchConverters * Test pytorch * Finish up torch tests * yapf * yapf * Remove else commit 3037747f66f0d71d65b6c65745b4f8942c22f05a Author: Danny McCormick Date: Tue Nov 15 14:13:04 2022 -0500 Fix broken notebook (#24179) commit b2b1c739ce37690923891934ee317f799db937a2 Author: MakarkinSAkvelon <67736809+MakarkinSAkvelon@users.noreply.github.com> Date: Tue Nov 15 21:53:06 2022 +0500 [Playground] Move Playground in GKE and Infrastructure change (#23928) * changes to updated master branch * Change workflow * ingress changes * Certificate was added * Updates for cloud build backend * Update main.tf * Create main.tf * Create variables.tf * Update variables.tf * Update main.tf * Update variables.tf * Update main.tf * Create output.tf * Update output.tf * Update output.tf * Update main.tf * Update build.gradle.kts * Update output.tf * Update main.tf * Update main.tf * Update main.tf * Update variables.tf * Update main.tf * Update variables.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update variables.tf * Update main.tf * Update variables.tf * Update main.tf * Update variables.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update output.tf * Update main.tf * Update main.tf * Update output.tf * Create variables.tf * Update main.tf * Update main.tf * Delete playground/terraform/infrastructure/cluddns directory * Update main.tf * Update output.tf * Update output.tf * Update build.gradle.kts * Update build.gradle.kts * Update build.gradle.kts * Update build.gradle.kts * Update build.gradle.kts * Update build.gradle.kts * Update README.md * Update README.md * helm folder name was changed * Update README.md * Update build.gradle.kts * Update build.gradle.kts * Update build.gradle.kts * Updates to readme * Fix DNS name * HelmChart was changed * Some workflows were changed * Remove unused file * playground-examples return * add license information * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * remove "stg" folder * Update README.md * Remove unused files * DNS Removed * var name changed * remove DNSName from var file * 1 * Clear terraform * remove unused records * gradle check * grade last change * issue fix * fix * 1 * run * test * Index creation for Gradle * Add IndexCreation in gradle * Update README.md * Update README.md * Fix names for Frontend * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Redis fix * services fix * Update variables.tf * change order in gradle * Fix Config.g.dart file issue * Update README.md * Playground workflow update Co-authored-by: Sergey Makarkin Co-authored-by: Sergey Makarkin Co-authored-by: ruslan-ikhsan Co-authored-by: Alex Kosolapov commit 85df5f2eb2f299e28b36be0cce7b9c19d62124da Author: Yi Hu Date: Tue Nov 15 11:38:13 2022 -0500 Eliminate CalciteUtil.CharType logical type (#24013) * Eliminate CalciteUtils.CharType logical type * Replace CalciteUtils.CharType to String Note that CalciteUtils still omits the precision of BINARY/VARBINARY/CHAR/VARCHAR as what it originally did. Support of the precision of these calcite types involves make use of making use of the overload method RelDataTypeFactory.createSqlType(var1, var2). * Replace every reference of CalciteUtil.CharType to generic PassThroughLogicalType check * Add TODO to Support sql types with arguments * Use VariableString in LogicalTypeTestCase commit f349f41010c5b238ff6020f7de718f938eef3c5e Author: alexeyinkin Date: Tue Nov 15 20:04:01 2022 +0400 Configure flutter_code_editor options with Hugo shortcode (#23926) (#24031) * Configure flutter_code_editor options with Hugo shortcode (#23926) * Minor fixes (#23926) * Refactor after review (#23926) commit 0f4ca6363b3ce0e5de3ad36517bb406aa6391a18 Author: Rebecca Szper <98840847+rszper@users.noreply.github.com> Date: Tue Nov 15 06:10:13 2022 -0800 Editorial review of the ML notebooks. (#24125) * Editorial review of the ML notebooks. * Editorial review of the ML notebooks. * Editorial review of the ML notebooks. * Update examples/notebooks/beam-ml/custom_remote_inference.ipynb Co-authored-by: Danny McCormick * Updating based on feedback * Update examples/notebooks/beam-ml/run_inference_sklearn.ipynb Co-authored-by: Danny McCormick * Update examples/notebooks/beam-ml/run_inference_tensorflow.ipynb Co-authored-by: Danny McCormick * Update examples/notebooks/beam-ml/run_inference_tensorflow.ipynb Co-authored-by: Danny McCormick * Update examples/notebooks/beam-ml/run_inference_tensorflow.ipynb Co-authored-by: Danny McCormick * Updating based on feedback Co-authored-by: Danny McCormick commit 5bd34ede026253326ebff1a7e4f9edb5f71b4a2c Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Nov 15 07:17:28 2022 -0500 Bump github.com/aws/aws-sdk-go-v2/feature/s3/manager in /sdks (#24131) Bumps [github.com/aws/aws-sdk-go-v2/feature/s3/manager](https://github.com/aws/aws-sdk-go-v2) from 1.3.2 to 1.11.39. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.3.2...feature/s3/manager/v1.11.39) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/feature/s3/manager dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 2ee809fa0ca7689dd0279e186ebc02d9569a8429 Merge: e3b9bdb2e6 563c66d6fd Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Tue Nov 15 11:01:14 2022 +0100 Merge pull request #23065: [Website] Update copy icon styles commit e3b9bdb2e607d85a4017ba7839000e92a0ad83c4 Author: Moritz Mack Date: Tue Nov 15 10:40:50 2022 +0100 [Dockerized Jenkins] Fix build of dockerized jenkins (fixes #24053) (#24054) commit faaac2ab6e010374cb2be0e95a5dd345836a2a2c Author: Moritz Mack Date: Tue Nov 15 10:38:59 2022 +0100 [Dockerized Jenkins] Update README how to use local repo (#24055) commit 689e70b5131620540faf52e2f1e2dca7a36f269d Author: Damon Date: Mon Nov 14 17:34:29 2022 -0800 Implement embedded WebAssembly example (#24081) commit e1bf6c42950e8013f35e35fb9fee8017e01e5010 Merge: eddac84126 10337d2868 Author: Robert Bradshaw Date: Mon Nov 14 15:22:14 2022 -0800 Merge pull request #24160 Rename the test_splits flag to direct_test_splits. commit eddac841261228a2c63fa9b225c520ae0f853806 Author: Pablo Date: Mon Nov 14 15:05:05 2022 -0800 More dataset templates to clean up (#24162) commit 2adb68bd12743566cc89b596bf204d7c807eb62d Author: Pablo Date: Mon Nov 14 13:28:13 2022 -0800 Adding a quickstart to README for the TS SDK (#23509) * More of a quickstart for the TS SDK * Update sdks/typescript/README.md Co-authored-by: Danny McCormick * Update sdks/typescript/README.md Co-authored-by: Danny McCormick Co-authored-by: Danny McCormick commit 10337d28685ad5712e2ad8608977ec5c5e0e6b6b Author: Robert Bradshaw Date: Mon Nov 14 12:46:32 2022 -0800 Rename the test_splits flag to direct_test_splits. This avoids possible flag conflicts. commit 48c70cc30742b45b17a1d18ece2f0d079bee3915 Author: arne-alex <108519096+arne-alex@users.noreply.github.com> Date: Mon Nov 14 21:33:02 2022 +0100 Merge pull request #23333: Track time on Cloud Dataflow streaming data reads and export via heartbeats commit 9c83de646ab52bd0b05e3346190dd55cd68b2a8b Author: Johanna Öjeling <51084516+johannaojeling@users.noreply.github.com> Date: Mon Nov 14 21:19:44 2022 +0100 Add more tests for S3 filesystem (#24138) commit 9e9c6d797ba52b460f83131431c8e53aebbbc9ac Merge: d5d76b9745 c600444e1d Author: Ning Kang Date: Mon Nov 14 12:06:15 2022 -0800 Merge pull request #24029 from apache/dependabot/npm_and_yarn/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/loader-utils-1.4.1 Bump loader-utils from 1.4.0 to 1.4.1 in /sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel commit d5d76b974592d45de368ab641647ca5cc4ec12ec Author: Yi Hu Date: Mon Nov 14 15:03:28 2022 -0500 Support SqlTypes Date and Timestamp (MicrosInstant) in AvroUtils (#23969) * Support SqlTypes Date and Timestamp (MicrosInstant) in AvroUtils * Add TODO about java.time migration commit 330cc2010c9f4a2d4e30318bf50a4109ec1cd392 Author: Pablo Date: Mon Nov 14 12:02:10 2022 -0800 Cleanup stale BQ datasets (#24158) * Cleanup stale BQ datasets * addressing comments commit 4a044999b8ed4bcd41f816f3a23ccb5da00c4c38 Merge: e563b9dd2f 5bd75c25de Author: Heejong Lee Date: Mon Nov 14 11:16:00 2022 -0800 Merge pull request #24076 from chamikaramj/multilang_java_updates Updates Multi-lang Java quickstart commit e563b9dd2f3aa0484e6cdc08869991b5e438023e Author: Evgeny Antyshev Date: Mon Nov 14 20:56:35 2022 +0300 [Tour Of Beam] verify that unit exists when saving progress (#24118) * AIO * Update learning/tour-of-beam/backend/integration_tests/auth_test.go Co-authored-by: Danny McCormick * nit Co-authored-by: Danny McCormick commit 774923e0dd089de870bfa5c77063ae2b28f79347 Merge: 71785de528 1ad0cbc445 Author: Kenn Knowles Date: Mon Nov 14 09:52:26 2022 -0800 Merge pull request #24141: Fix checkArgument format in GcsPath commit 71785de52864313c2e3b14fe72a2a63281343617 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Nov 14 11:54:37 2022 -0500 Bump github.com/aws/aws-sdk-go-v2/config from 1.17.10 to 1.18.0 in /sdks (#24151) Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.17.10 to 1.18.0. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.17.10...config/v1.18.0) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/config dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 50d591d6cb3e799bee4e29dfc593c693a86e6276 Author: Bruno Volpato Date: Mon Nov 14 11:50:01 2022 -0500 Change DataflowBatchWorkerHarness doWork error level to INFO (#24135) commit 5a72696bfda09fdb905ba8e58b636f8494ef955f Merge: ee0a5836d6 0633fe9634 Author: Kenn Knowles Date: Mon Nov 14 08:12:12 2022 -0800 Merge pull request #24149: Remove extraneous jetbrains annotation commit ee0a5836d69b776834eb3bd9b2bd02eb5252c333 Merge: d001a69e1a 137799672e Author: Kenn Knowles Date: Mon Nov 14 08:11:00 2022 -0800 Merge pull request #24132: Fix checkArgument format string in AvroIO commit d001a69e1a58701d6ed4fcb5e3fb7a0921301dad Author: Yi Hu Date: Mon Nov 14 10:56:54 2022 -0500 Test Dataproc 2.1 with Flink load tests (#24129) * Test Dataproc 2.1 with Flink load tests * Minor fix flink_cluster script commit caabd9be52887ad70c8a4269395c893811ac6a84 Author: Israel Herraiz Date: Mon Nov 14 16:03:39 2022 +0100 Make MonotonicWatermarkEstimator work like its Java SDK equivalent (#24146) * Make MonotonicWatermarkEstimator work like its Java SDK equivalent The current implementation of MonotonicWatermarkEstimator raises an exception with late messages, which makes the watermark estimator barely usable in real world scenarios. This PR fixes #20041 by making this watermark estimator work like its Java SDK equivalent (`WatermarkEstimators.MonotonicallyIncreasing`). * Update unit tests too * Make linter happy commit 451f6b3e7f58d0a3782ad942c6a1fd9f63932024 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Nov 14 09:48:23 2022 -0500 Bump golang.org/x/net from 0.1.0 to 0.2.0 in /sdks (#24153) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.1.0 to 0.2.0. - [Release notes](https://github.com/golang/net/releases) - [Commits](https://github.com/golang/net/compare/v0.1.0...v0.2.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 2bb03d62e2d7dc2d8e39040fc9adebccbde74fde Merge: 4e39ef2041 623083cd0a Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Mon Nov 14 15:01:13 2022 +0100 Merge pull request #24000: [Website] Change headers size from h4,h3 to h2 commit 563c66d6fd32165da14a07747f2764c17a5d24ea Author: bulat safiullin Date: Wed Sep 7 18:28:42 2022 +0600 [Website] update pre tag copy link styles #23064 commit 4e39ef20410ee51c6040317bcd60171e64c5171f Merge: 223768f782 105ed6fedc Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Mon Nov 14 10:55:33 2022 +0100 Merge pull request #24115: [Website] update go-dependencies.md java-dependencies.md links commit 223768f782f771f0033b8d0686d86cf4c71fad75 Merge: aa0a35dabf a9da2abee6 Author: Kenn Knowles Date: Sun Nov 13 18:53:13 2022 -0800 Merge pull request #24136: Fix checkArgument format string in ExecutionStateTracker commit 0633fe9634fe61df7cbc0ecac205d81124fd504a Author: Kenneth Knowles Date: Sat Nov 12 15:15:16 2022 -0800 Remove extraneous jetbrains annotation commit 83f1bc19b95935e60ca1f4027d4b60c7e738a84a Author: Kenneth Knowles Date: Sat Nov 12 14:16:09 2022 -0800 Fix arguments to checkState in BatchViewOverrides commit 1ad0cbc44594d8405bf4b07a126265238013a02a Author: Kenneth Knowles Date: Sat Nov 12 13:41:02 2022 -0800 Fix checkArgument format in GcsPath commit aa0a35dabf9c2a0d9822faff06d939d9a77a3ab6 Author: Kenn Knowles Date: Fri Nov 11 20:26:30 2022 -0800 Fix checkArgument format string in TestStream (#24134) commit a9da2abee6455bc2cf0f18ba5f6cd7bbaeae669f Author: Kenneth Knowles Date: Fri Nov 11 16:54:27 2022 -0800 Fix checkArgument format string in ExecutionStateTracker commit 369e2ba8622d3474c14c39b941b2c618842d1e47 Author: Ryan Thompson Date: Fri Nov 11 19:46:07 2022 -0500 Add a ValidatesContainer integration test for use_sibling_sdk_workers (#24099) commit 137799672eb559a7586262e6a8a73d1ab3580e44 Author: Kenneth Knowles Date: Fri Nov 11 15:30:01 2022 -0800 Fix checkArgument format string in AvroIO commit 5d2dbf957e4e82fb3980726940df02ac67e563cd Author: Anand Inguva <34158215+AnandInguva@users.noreply.github.com> Date: Fri Nov 11 15:57:28 2022 -0500 Update staging of Python wheels (#24114) Fixes https://github.com/apache/beam/issues/24110 commit c2021bee1eba0322b43c90841397859048296b21 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri Nov 11 15:33:14 2022 -0500 Bump google.golang.org/api from 0.102.0 to 0.103.0 in /sdks (#24049) Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.102.0 to 0.103.0. - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.102.0...v0.103.0) --- updated-dependencies: - dependency-name: google.golang.org/api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 6557c91c79480b9d90573d52d257a11c2b160196 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri Nov 11 11:47:12 2022 -0800 Bump github.com/aws/aws-sdk-go-v2/service/s3 in /sdks (#24112) Bumps [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) from 1.29.1 to 1.29.2. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.29.1...service/s3/v1.29.2) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/service/s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 96f9da1ab652156cd143d57e3aa3d94836338f2b Author: Yi Hu Date: Fri Nov 11 14:34:22 2022 -0500 More cleanup containers (#24105) * More cleanup containers * prebuilt_beam_sdk/beam_python_prebuilt_sdk no longer exists in gcr.io Add correct paths to cleanup * Bump grace time to 15 days * Run job daily as in code comment * Set grace period to 30 days commit 836766ddb83d37463e4b036f156b8d7e15e3864b Author: Ritesh Ghorse Date: Fri Nov 11 14:30:30 2022 -0500 upgrade testcontainer dependency (#24123) commit 9fcd20c3712536f2d4580beead678cdbb6fd4746 Author: Damon Date: Fri Nov 11 11:12:11 2022 -0800 Implement PubsubRowToMessage transform (#23897) * Begin PubsubRowToMessage Impl * Complete working draft * Unit tests validate user and non-user fields * Finish tests on supporting methods * Pass checks before finalizing tests * WIP * fix timestamp * finalize tests * Finalize code comments * Clean up check findings * Add InputSchemaFactory * Patch code comment typo commit 3a6fcc1ca4d07a467464ed1214a94b5c9c147295 Author: Evgeny Antyshev Date: Fri Nov 11 19:13:45 2022 +0300 disable (#24121) commit 027fb142038b45c443d87af96cac082264c43188 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri Nov 11 10:26:23 2022 -0500 Bump cloud.google.com/go/bigtable from 1.17.0 to 1.18.0 in /sdks (#24113) Bumps [cloud.google.com/go/bigtable](https://github.com/googleapis/google-cloud-go) from 1.17.0 to 1.18.0. - [Release notes](https://github.com/googleapis/google-cloud-go/releases) - [Changelog](https://github.com/googleapis/google-cloud-go/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-cloud-go/compare/pubsub/v1.17.0...pubsub/v1.18.0) --- updated-dependencies: - dependency-name: cloud.google.com/go/bigtable dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit b2d28a64bb0837dd97e8be7f97f31f88d380f110 Author: Danny McCormick Date: Fri Nov 11 08:45:14 2022 -0500 Add TFX support in pydoc (#23960) * Add TFX support in pydoc * Wording commit 105ed6fedcb6ff33d4a43940c342a653e67cb25e Author: bulat safiullin Date: Thu Nov 10 17:47:54 2022 +0600 [Website] update go-dependencies.md java-dependencies.md programming-guide.md links #24084 commit 4b96193250a63b27721a8c5e1a3bd6ecff983093 Author: Brian Hulette Date: Thu Nov 10 16:51:06 2022 -0800 Remove TheNeuralBit from the pool of Python reviewers (#24108) commit 8f8f089a5f565f179905984cef3522a0577d9219 Author: Sanil Jain Date: Thu Nov 10 16:47:31 2022 -0800 Wire SamzaPipelineOptions to Exeption listener interface (#24109) commit b3186ba91f9bb22764d47b78eb2b7ff017080f75 Author: Ahmed Abualsaud <65791736+ahmedabu98@users.noreply.github.com> Date: Thu Nov 10 18:04:50 2022 -0500 Support using BigQueryIO Storage Read API with SchemaTransforms (#23827) * support schema transform for bq direct read method * use vendor Strings import * add BigQueryServices argument to config object * suppress nullability errors * add package-info.java file to providers subdirectory * removing accidentally created file * added documentation and moved configuration filclass into provider class * validate config params before expansion. config has a validaate me method * updated URN identifier to follow standards commit a4a94da1936d8cd2f8d1145fd2e8329fe06a2990 Author: Oleh Borysevych Date: Fri Nov 11 00:28:43 2022 +0200 fixing linter error (#24104) commit 156a6099d71a155c3379340a0b98256306e1755e Author: Danny McCormick Date: Thu Nov 10 17:26:15 2022 -0500 Add blog post on new ML resources (#24071) * Create ml-resources.md * Add ensemble notebook image * Add image link * Fix image link * Add ml-landing page image * Add image + move around * Add paragraph on upcoming changes * Remove bad whitespace commit 38742d40c895f5d38ee6ee5eb328d11b3262307e Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu Nov 10 16:12:40 2022 -0500 Bump github.com/aws/aws-sdk-go-v2/config from 1.5.0 to 1.17.10 in /sdks (#24080) Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.5.0 to 1.17.10. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.5.0...config/v1.17.10) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/config dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 92cef32915c40d353b51529a87d8f0131b0a3538 Author: BjornPrime <32173247+BjornPrime@users.noreply.github.com> Date: Thu Nov 10 15:30:37 2022 -0500 Num failed inferences (#23830) * created test_increment_num_failed_inferences and test_num_failed_inferences_no_failures * added assertRaises to test_increment_num_failed_inferences * added num_failed_inferences to _MetricsCollector * changed error handling and update() implementation * updated metric name in tests * removed unnecessary else blocking * removed unnecessary inference_args from test_increment_failed_batches_counter() * changed final test_increment_failed_batches_counter assertion * clarified error handling and updated failed_batches_counter initialization * decreased examples array length to 1 to ensure repeatability * troubleshooting tests * trying to get test_increment_failed_batches_counter to fail as expected * corrected assertion details * simplified assertRaises and added reminder comment to assertEqual counter * lint test * lint test passed, resetting pre-commit-config.yaml * fixed lingering linting issues * shortened comment line to comply with linting * formatter worked its magic commit 2341f61d48d838ddaf2e4fb990a49987244c3513 Author: Evgeny Antyshev Date: Thu Nov 10 21:24:55 2022 +0300 [Tour Of Beam] handle CORS pre-flight requests (#24083) * cors * README * nit * nit * -headers, -cache * allow-headers * +1h cache,comment commit 36b0c8f1a76865e4dc3b1eaec1566c3ef9fd4345 Author: Evgeny Antyshev Date: Thu Nov 10 21:21:21 2022 +0300 [Playground] update snippet by persistence_key (#24056) * proto * AIO * -frontend * testify * +license * -build * index * skipKey * Update playground/backend/internal/db/datastore/datastore_db.go Co-authored-by: Danny McCormick Co-authored-by: Danny McCormick commit df553d1a4c6c6cc9b37ada2a6c84c88d8aef38b9 Author: Ahmed Abualsaud <65791736+ahmedabu98@users.noreply.github.com> Date: Thu Nov 10 13:17:36 2022 -0500 Add random string at the end of BigQuery query job name to make it resilient to retries (#24041) * add random string at the end of query job name * use deterministic temp table name commit e439f4120ef4c25aa36e5b03756dc7391bdbd211 Author: Pablo Date: Thu Nov 10 10:06:26 2022 -0800 Improving stale container cleanup script (#24040) * Improving stale container cleanup script * Avoid also latest image * Update .test-infra/tools/stale_dataflow_prebuilt_image_cleaner.sh Co-authored-by: Yi Hu * Update .test-infra/tools/stale_dataflow_prebuilt_image_cleaner.sh Co-authored-by: Yi Hu Co-authored-by: Yi Hu commit 8d585242e158babd8dd2ca5a6d5a49d353be2935 Author: Anand Inguva <34158215+AnandInguva@users.noreply.github.com> Date: Thu Nov 10 12:58:41 2022 -0500 [Python]Set pickle library at the Pipeline creation stage (#24069) Fixes https://github.com/apache/beam/issues/21615 commit 08b6a524fecc333a12ce42971733ef64ae7d02f1 Author: Janek Bevendorff Date: Thu Nov 10 18:37:09 2022 +0100 [BEAM-12792] Install pipline dependencies to temporary venv (#16658) commit 74f87b0282a23aa01ecb63288013311d207960aa Merge: 38a85b288a 383ea77bc9 Author: Robert Bradshaw Date: Thu Nov 10 09:10:37 2022 -0800 Merge pull request #23985 Support dynamic sharding in the worker. commit 38a85b288ad10171c444d4092eb969ca5de58af3 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu Nov 10 10:39:15 2022 -0500 Bump github.com/aws/aws-sdk-go-v2/service/s3 in /sdks (#24077) Bumps [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) from 1.11.1 to 1.29.1. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.11.1...service/s3/v1.29.1) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/service/s3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit c5110bae06fb9db6cace1f7657745fa97e3f58af Author: Yi Hu Date: Thu Nov 10 10:33:55 2022 -0500 Fix FhirIO javadoc format broken (#24072) commit 623083cd0a72d86c7ecba7653e9a8564861abc4d Author: bulat safiullin Date: Mon Nov 7 16:08:39 2022 +0600 [Website] change headers size from h4,h3 to h2 #24082 commit 5bd75c25de291e517cc5c5799ae4adaaaaceacb7 Author: Chamikara Jayalath Date: Wed Nov 9 18:04:28 2022 -0800 Updates Multi-lang Java quickstart commit 4522f4ce916223afb3c4edd02a7be6018d0ce5a4 Author: Trevor Gevers Date: Wed Nov 9 18:56:18 2022 -0600 Update datastore_wordcount.py (#23724) commit 96cc252348ce7229731be3c74bf5848d1b004c08 Author: tvalentyn Date: Wed Nov 9 16:08:00 2022 -0800 Remove a duplicate label (#24043) commit 62a6bd1e9317a7658810e9a0eebfe925460e8982 Author: Thiago Nunes Date: Thu Nov 10 08:45:27 2022 +1100 test: add more tests to throughput estimator (#23915) Verifies that getting the throughput when no updates have occurred for the size of the window should return 0. commit e6647c34bb367b3058c42d0201150395c534e7ce Author: Ritesh Ghorse Date: Wed Nov 9 15:12:59 2022 -0500 skip output coder field in exp request (#24066) commit 383ea77bc982416afcbbbe11a4dc1f1424670589 Author: Robert Bradshaw Date: Wed Nov 9 10:49:37 2022 -0800 Reduce flakiness of time-based split manager test. Increase wait time from a tenth to half a second. commit 539fa9159ffc116b2e79e6de2804dfdd1c1e4722 Author: Danny McCormick Date: Wed Nov 9 11:45:20 2022 -0500 Convert initialisms to all caps (#24061) * Convert initialisms to all caps * Fix test refs commit 4941b9633c6ccf9eb8aad554186aac24ca7b7492 Author: Ryan Thompson Date: Wed Nov 9 11:25:48 2022 -0500 added comments for tensorflow notebook (#23726) * added comments for tensorflow notebook * added note to string type commit 858f5048f578548a63e5e4319a7ab5363311c269 Merge: 95c121b254 1929968891 Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Wed Nov 9 16:35:19 2022 +0100 Merge pull request #24057: [Spark Dataset runner] Enable projection pushdown for Spark dataset runner commit 95c121b2549d3f8fda7668e3759b8991b55d9865 Author: Oleh Borysevych Date: Wed Nov 9 16:03:33 2022 +0200 Fix dependency mismatch in Playground Java runner (#24059) * fixing existing and potential dependency mismatch * extract grpc version commit 1929968891d629c83249c574c28db6c103ba9271 Author: Moritz Mack Date: Wed Nov 9 13:35:12 2022 +0100 [Spark Dataset runner] Enable projection pushdown for Spark dataset runner. commit 63362f5ba60a22e77e54c2df47a844f031036309 Author: Johanna Öjeling <51084516+johannaojeling@users.noreply.github.com> Date: Wed Nov 9 07:49:54 2022 +0100 [Go SDK] S3 implementation of the Beam filesystem (#23992) * Implement filesystem for S3 * Update CHANGES.md commit 73142bad2472e4516831c24a8dfb05c9acebf791 Author: Kanishk Karanawat Date: Tue Nov 8 20:46:04 2022 -0500 Handle Avro schema generation for logical data types in BigQueryAvroUtils (#23620): handle avro logical types for TableFieldSchema to Avro schema conversion Co-authored-by: Kanishk Karanawat commit 8db8fae173056c0d89a36a8a5ce0443b6b9e54fa Author: Robert Burke Date: Tue Nov 8 15:56:53 2022 -0800 [Go] Add pipeline resource hints to CHANGES.md (#24036) commit a84b7dc179fed5dfc1d48dddfb04266de3716e31 Author: Robert Bradshaw Date: Mon Nov 7 16:35:25 2022 -0800 Make mypy happy. commit b9655e7de1a682d8ec4efcafb4d610f794e1b40e Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Nov 8 12:27:38 2022 -0800 Bump cloud.google.com/go/storage from 1.27.0 to 1.28.0 in /sdks (#24028) Bumps [cloud.google.com/go/storage](https://github.com/googleapis/google-cloud-go) from 1.27.0 to 1.28.0. - [Release notes](https://github.com/googleapis/google-cloud-go/releases) - [Changelog](https://github.com/googleapis/google-cloud-go/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-cloud-go/compare/spanner/v1.27.0...spanner/v1.28.0) --- updated-dependencies: - dependency-name: cloud.google.com/go/storage dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 708e05f0dc6c0a2e62674cd0ecb8a6744ae57d3a Author: Brian Hulette Date: Tue Nov 8 12:18:23 2022 -0800 Retroactively announce Batched DoFn support in 2.42.0 Blog (#24011) * Retroactively announce Batched DoFn support in 2.42.0 * Add to blog as well commit b9ff75a18b40141a8d2340e397fd70382b3d4e8f Author: Israel Herraiz Date: Tue Nov 8 20:03:43 2022 +0100 Update my Twitter handle (#23653) commit bf621ccb88023e0bc09752978c099ac4629086e2 Author: Rebecca Szper <98840847+rszper@users.noreply.github.com> Date: Tue Nov 8 10:50:02 2022 -0800 Editorial review of the ML base API descriptions (#24026) commit f0a6ff46619ee1fd0639fa3f06e04708f69dee74 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Nov 8 13:04:03 2022 -0500 Bump cloud.google.com/go/bigtable from 1.16.0 to 1.17.0 in /sdks (#24027) Bumps [cloud.google.com/go/bigtable](https://github.com/googleapis/google-cloud-go) from 1.16.0 to 1.17.0. - [Release notes](https://github.com/googleapis/google-cloud-go/releases) - [Changelog](https://github.com/googleapis/google-cloud-go/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-cloud-go/compare/pubsub/v1.16.0...pubsub/v1.17.0) --- updated-dependencies: - dependency-name: cloud.google.com/go/bigtable dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 7dac3f5ef40b5d24b24d9ce5bec4717284260b85 Author: Lukasz Cwik Date: Tue Nov 8 09:42:29 2022 -0800 [#21250] Trivial removal of loop over something that always has one element (#24014) Multiplexing was put into the PCollectionConsumerRegistry a long time ago and this seems to have been missed during that migration. commit a6a9b23fd5b74142c35948f10d1840b882817246 Author: Robert Burke Date: Tue Nov 8 09:19:49 2022 -0800 [Go] Pipeline Resource Hints (#23990) commit 8cf2a63cc25399109f64b84ddfcd7c74d21e61ce Author: tvalentyn Date: Tue Nov 8 09:19:16 2022 -0800 Update release notes. (#23986) commit c600444e1dfa2f4afaad056bc65fa009a60a32bb Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Nov 8 06:22:14 2022 +0000 Bump loader-utils Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.1. - [Release notes](https://github.com/webpack/loader-utils/releases) - [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.1/CHANGELOG.md) - [Commits](https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.1) --- updated-dependencies: - dependency-name: loader-utils dependency-type: indirect ... Signed-off-by: dependabot[bot] commit 62d8bdc604dfeccae08d00225bce8c9b9c3ffb28 Merge: d4142f7eab 930c4d2d87 Author: Robert Bradshaw Date: Mon Nov 7 15:31:37 2022 -0800 Merge pull request #23789 Better surfacing of Scala support via Scio. commit 7f7713de09b3b0e400ed02ffdfcb34a6a8b6e1e4 Merge: 5f587b9339 d4142f7eab Author: Robert Bradshaw Date: Mon Nov 7 15:29:27 2022 -0800 Merge branch 'master' into javascript-liquid-sharding commit 5f587b9339b3b19ae5c5b1cf15e3ce218f75d21a Author: Robert Bradshaw Date: Mon Nov 7 15:25:33 2022 -0800 Clarifying comments. commit 60fe3cdddf9d3c27d9493b345d1f5f2a9284a76f Author: Robert Bradshaw Date: Mon Nov 7 15:06:26 2022 -0800 Update style sdks/python/apache_beam/runners/portability/fn_api_runner/fn_runner.py Co-authored-by: Danny McCormick commit d4142f7eab7d5a3d21a3d3930c448fe403880f93 Author: Robert Burke Date: Mon Nov 7 12:11:21 2022 -0800 Switch && for || to fix bug in #23889 resolution (#24017) commit 45100d708d954b25b5a884dc3c7a965f008228c6 Author: Danny McCormick Date: Mon Nov 7 14:53:24 2022 -0500 Add files then check cached diff to get untracked files commit 380d4730d3c52b5c2165bdb84aac11d0feccfe4f Author: scwhittle Date: Mon Nov 7 19:33:37 2022 +0100 Enforce splitting invariants by ensuring split state is reset in the same synchronized block as window index increments. (#23882) * Enforce splitting invariants by ensuring split state is reset in the same synchronized block as window index increments. Fixes #23881. * Add missing currentElement = null; Co-authored-by: Lukasz Cwik commit 8b3fd2e0d652045bf94b83638129bb12562ce738 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Nov 7 10:33:26 2022 -0800 Bump google.golang.org/api from 0.101.0 to 0.102.0 in /sdks (#23957) Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.101.0 to 0.102.0. - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.101.0...v0.102.0) --- updated-dependencies: - dependency-name: google.golang.org/api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 9533fc3757d3041135cbe2f5078dff0855adc1f1 Author: capthiron <24925821+capthiron@users.noreply.github.com> Date: Mon Nov 7 19:32:18 2022 +0100 feat: implement bigtable io connector with write capabilities (#23411) commit c4218e572aa8a8f46b433b60073a59fdd7fdf148 Merge: 23676a9ec1 a5ee669a43 Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Mon Nov 7 18:24:45 2022 +0100 Merge pull request #23934: [Website] change case studies page mobile layout commit 23676a9ec17069b309e8803d1fbfeb8009035828 Author: Oleh Borysevych Date: Mon Nov 7 17:24:59 2022 +0200 [Tour of Beam] Learning content for "Introduction" module (#23085) * learning content for introduction module * removing white spaces from md files * delete whitespaces * delete whitespaces in python * delete whitespace #2 * divide pipeline concepts * add pipeline example concepts * adding category tag to python examples * adding category to java examples * adding category to go examples * fixed go example * fixed go example compilation * fixing python duplicate example names * add runner concepts * fixing java examples * add licence for runner unit * some minor fixes for unit names * fixed unit name * resolving CR comments * adding complexity to examples * adding tags * fixed go example compilation * fixed python example with duplicate transform * change indent python * fixing missing pipeline options * change arrow symbol * delete example prefix * minor formatting and readability fixes * add example description * minor fix * minor code review comment Co-authored-by: Abzal Tuganbay commit 98d2ffd69ab9d5c49196a78f7c25daacb57b6478 Author: Brian Hulette Date: Mon Nov 7 07:03:12 2022 -0800 Make `documentation/io/connectors/` canonical (#23877) * Drop documentation/io/built-in/ * Update links in Custom I/O pattern commit c0b41fa045418beb782c0a59e6f5c511da898c53 Author: Danny McCormick Date: Mon Nov 7 09:29:08 2022 -0500 Use git diff instead of git diff-index to avoid file timestamp changes being picked up commit 0476d6498217b7b0e833643c47fef2c4bdaec529 Merge: 1d5fc14031 6ae37b6f82 Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Mon Nov 7 15:28:59 2022 +0100 Merge pull request #23962: [CdapIO] Add sparkreceiver:2 module. commit 1d5fc14031d583e92018ebfbeaff9b4e3b978fdb Author: Danny McCormick Date: Mon Nov 7 09:14:24 2022 -0500 Remove quiet flag on debug commit c08273b9355566181d2d5c0792130f8d5cc1428c Author: Danny McCormick Date: Mon Nov 7 09:12:26 2022 -0500 Correctly print diff and swallow empty commits for the moment commit 66fb431deb77db5f7f0fac31e6bf3b2c094c8ac5 Author: Danny McCormick Date: Mon Nov 7 09:08:53 2022 -0500 Print diff and scope to state path commit e0e10b9e5432643b884c381d145e5924cc4ef193 Author: Danny McCormick Date: Sun Nov 6 12:12:22 2022 -0500 PR Bot - Dont throw error on return code 1 commit bbcb790461c47d22399c681cd42c434b206eb550 Author: Danny McCormick Date: Sun Nov 6 11:59:32 2022 -0500 Fix pr bot - exec doesn't allow command chaining commit 88f9a66a9f4cc2fe3259d5ebd83ebb472a29dd5e Author: Danny McCormick Date: Sun Nov 6 11:46:34 2022 -0500 Fix diff to stop repeated bot runs commit ddb4f2d53538fea68383fe43221d4074d05d11b9 Author: bullet03 Date: Fri Nov 4 16:11:10 2022 -0700 Website add and update logos (#23899) * [Website] add and update logos * Delete talend.svg:Zone.Identifier commit 6d42219ff547720996489aa29de0d64246db2541 Author: Robert Bradshaw Date: Fri Nov 4 14:30:18 2022 -0700 Enable more portable-runner requiring tests. (#23970) * Enable more portable-runner requiring tests. * Run all basic tests on portable runner as well. * Mark ULR tests. commit 1a643d16112a5f3f1418f1be393de51af65d752b Author: David Cavazos Date: Fri Nov 4 13:45:12 2022 -0700 Beam starter projects blog post (#23964) Co-authored-by: Ahmet Altay commit d10b4a28fff667289c146152535275035f2dedf7 Author: Ryan Thompson Date: Fri Nov 4 16:06:49 2022 -0400 removed trailing whitespace (#23987) commit 3bd697561aab4a5d2aa49d29143695d6d57a834a Author: Robert Bradshaw Date: Fri Nov 4 11:43:47 2022 -0700 Add dynamic splitting support to the worker. commit ed520243f472c7224a1f8c74a0c2e8f81965cbfc Author: Robert Bradshaw Date: Fri Nov 4 11:07:40 2022 -0700 Add the a Reshuffle operation and use it in Create. This allows created sources to be staticly and dynamically split. commit 9283512544b8de169be9cd7795b42284fdf45b87 Author: Robert Bradshaw Date: Fri Nov 4 10:28:51 2022 -0700 Add the ability to schedule splits on the ULR via a pipeline option. This can be used to test arbitrary SDKs for behavioral correctness for dynamic splitting. These splits are wall-time based, which isn't ideal, but easier than setting up and managing a cross-process synchronization channel. commit ed7b560d7ce7dda0b55a067b9d9a1a9d692a7d7a Author: Robert Bradshaw Date: Fri Nov 4 09:46:19 2022 -0700 Compute element counts for all PCollections. commit 1cfdb127983a55c77b3259c4fdd248497b28e250 Author: Jack McCluskey <34928439+jrmccluskey@users.noreply.github.com> Date: Fri Nov 4 15:43:16 2022 -0400 Add custom inference fn suport to the sklearn model handlers (#23642) * Add custom inference fn suport to the sklearn model handlers * Clean up import order * Update typing, add numpy unit test * Add Pandas unit test * Formatting, linting * yapf run * Remove trailing whitespace * import order * Change inference_fn to keyword-only arg commit 8617b86fd792ac555233dd79c8ede34c2ce67ecf Merge: aa178f8252 2496a0d1e0 Author: Robert Bradshaw Date: Fri Nov 4 11:42:21 2022 -0700 Merge pull request #23978 Add basic counter support to the typescript SDK. commit 2496a0d1e0fda74e8fc0f24eee011362426369a2 Merge: 64abcbe4a3 aa178f8252 Author: Robert Bradshaw Date: Fri Nov 4 11:15:47 2022 -0700 Merge branch 'master' into javascript-metrics commit aa178f825223cbb0a6208fad0e02f98292eeded1 Merge: 97628802fe 1807c307aa Author: Robert Bradshaw Date: Fri Nov 4 09:34:11 2022 -0700 Merge pull request #23976 Correctly capture log levels and attach stage information. commit 64abcbe4a3a15160aba3f3163ff8cbf5186bbfdb Author: Robert Bradshaw Date: Fri Nov 4 09:27:22 2022 -0700 Only report counters that were actually used. commit 1807c307aa1e493acb2d8ba542baffefcb96e7e2 Author: Robert Bradshaw Date: Fri Nov 4 08:52:21 2022 -0700 Remove obsolete TODO. commit 97628802fe4cf6640a3b6854e27b410dd5731379 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri Nov 4 11:47:07 2022 -0400 Bump cloud.google.com/go/datastore from 1.8.0 to 1.9.0 in /sdks (#23916) Bumps [cloud.google.com/go/datastore](https://github.com/googleapis/google-cloud-go) from 1.8.0 to 1.9.0. - [Release notes](https://github.com/googleapis/google-cloud-go/releases) - [Changelog](https://github.com/googleapis/google-cloud-go/blob/main/documentai/CHANGES.md) - [Commits](https://github.com/googleapis/google-cloud-go/compare/asset/v1.8.0...asset/v1.9.0) --- updated-dependencies: - dependency-name: cloud.google.com/go/datastore dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 058c56af735e10184d1501cc08cd16af4d21e64a Author: Ayush Sharma <114604338+ayushthe1@users.noreply.github.com> Date: Fri Nov 4 20:58:11 2022 +0530 [Task]: PR Bot will push commits only if they are non-empty (#23937) * fix pr-bot * fix the git pr bot commit 7dba78d611089a1826c5655ed7ffcdf3f6007eae Author: Danny McCormick Date: Fri Nov 4 09:35:16 2022 -0400 Immediately truncate full restriction on drain of periodic impulse (#23765) * Immediately truncate full restriction on drain of periodic impulse * Whitespace format commit 16852518861514a56ad1b57113e3815cfcc8533a Author: Anand Inguva <34158215+AnandInguva@users.noreply.github.com> Date: Fri Nov 4 08:39:34 2022 -0400 TFX image classification example (#23456) * TFX image classification example * TFX image classification with serving model * Add TF Model Wrapper * Clean up code * Refactoring * Add a test for tfx_bsl RunInference * fixup lint * Refactoring * Fixup lint * Add brief summary for the example * Apply suggestions from code review Co-authored-by: Andy Ye * Refactoring code and add comments * Update help description * reorder imports * Reorder imports again * Add docstring * Refactoring * Add pillow to tfx pipeline requirements * Move inferencePostCommitIT to Python 3.9 suite * Uncomment other postcommit suites Co-authored-by: Andy Ye commit 30b26171b4038c1c976adbc3be386e118b35153b Author: Danny McCormick Date: Fri Nov 4 08:22:17 2022 -0400 Update watermark during periodic sequence/impulse (#23507) * Update watermark during periodic sequence/impulse * Remove extraneous import * Formatting * Linting * Only run on dataflow for guaranteed watermark support * More permissive test to avoid timing issues * Test pipeline options * Fix test * Formatting * Formatting * Apply feedback - cleanup/naming/flink * Format * Unused import commit 1563b9721b4bee5a22d384b282762726247e0703 Author: Brian Hulette Date: Fri Nov 4 05:09:39 2022 -0700 Improve Iterator error message (#23972) commit e3987b5435d39c5fb058d4085eb5e210f8756224 Author: Robert Bradshaw Date: Thu Nov 3 17:39:49 2022 -0700 old prettier change commit 89c8dd5ca23591be6c2778045df32c7d08d9f99e Author: Robert Bradshaw Date: Thu Nov 3 17:12:26 2022 -0700 Add distribution metric type. commit e4e606a8f2652c2fa761a95462f230385b6bcb47 Author: Robert Bradshaw Date: Thu Nov 3 17:09:03 2022 -0700 Support metrics over the portability API. commit e04f3d6fdb39528264cb2a14e60e565991121f1c Author: Robert Bradshaw Date: Thu Nov 3 16:52:51 2022 -0700 Add basic counter setting and getting to the typescript SDK. commit 1daa9c373ac7fbdb696120eeaa2ca9e85a679a1f Author: Robert Bradshaw Date: Thu Nov 3 16:01:59 2022 -0700 Cleanup worker logging. Attempt to correctly capture and propagate log levels and attaches stage information to them. Also remove some excessively verbose logs. commit d3a173cf16355bfe23a9d918afa12cd61d290b59 Author: Robert Bradshaw Date: Thu Nov 3 15:11:40 2022 -0700 Move logging to its own module. commit 6ae37b6f82ae3cd77cc82aff4566d8218a8acc57 Author: vitaly.terentyev Date: Thu Nov 3 19:44:54 2022 +0400 Fix sparkreceiver dependencies commit 8223375d2f9606a29d6498a73c1914a61f3277c4 Author: vitaly.terentyev Date: Thu Nov 3 19:34:04 2022 +0400 Add sparkreceiver:2 module. commit a5ee669a439dc3d13dfc4926c1c5ae2351bb9135 Author: bulat safiullin Date: Wed Nov 2 13:53:08 2022 +0600 [Website] change case-study-card width on mobile commit 930c4d2d87d462b2457369fd06066203a6628a46 Author: Robert Bradshaw Date: Fri Oct 21 12:22:13 2022 -0700 Better surfacing of Scala support via Scio. draft working code test commit Revert "Squashed commit of the following:" This reverts commit 8fc833a5e7abf4cbfb63e56d450631bbfc1985ff. auth files --- .../frontend/lib/auth/method.dart | 27 +++ .../frontend/lib/auth/notifier.dart | 49 ++++++ .../frontend/lib/cache/cache.dart | 9 + .../frontend/lib/cache/user_progress.dart | 69 ++++++++ .../login/{login_button.dart => button.dart} | 29 +-- .../{login_content.dart => content.dart} | 25 ++- .../lib/components/profile/avatar.dart | 37 ++-- .../{profile_content.dart => user_menu.dart} | 64 +++++-- .../frontend/lib/components/scaffold.dart | 25 ++- .../tour-of-beam/frontend/lib/config.dart | 4 +- .../frontend/lib/firebase_options.dart | 63 +++++++ .../tour-of-beam/frontend/lib/locator.dart | 10 ++ learning/tour-of-beam/frontend/lib/main.dart | 5 + .../frontend/lib/models/user_progress.dart | 35 ++++ .../lib/pages/tour/controllers/unit.dart | 40 +++++ .../frontend/lib/pages/tour/state.dart | 7 + .../lib/pages/tour/widgets/content.dart | 81 ++++++--- .../lib/pages/tour/widgets/group_title.dart | 79 ++++++++- .../frontend/lib/pages/tour/widgets/unit.dart | 47 +++-- .../tour/widgets/unit_progress_indicator.dart | 57 ++++++ .../frontend/lib/pages/welcome/screen.dart | 57 ++++-- .../lib/repositories/client/client.dart | 5 + .../client/cloud_functions_client.dart | 42 +++++ .../models/get_user_progress_response.dart | 33 ++++ learning/tour-of-beam/frontend/pubspec.lock | 165 +++++++++++++++++- learning/tour-of-beam/frontend/pubspec.yaml | 6 + .../lib/playground_components.dart | 1 + .../lib/src/controllers/public_notifier.dart | 19 +- 28 files changed, 968 insertions(+), 122 deletions(-) create mode 100644 learning/tour-of-beam/frontend/lib/auth/method.dart create mode 100644 learning/tour-of-beam/frontend/lib/auth/notifier.dart create mode 100644 learning/tour-of-beam/frontend/lib/cache/cache.dart create mode 100644 learning/tour-of-beam/frontend/lib/cache/user_progress.dart rename learning/tour-of-beam/frontend/lib/components/login/{login_button.dart => button.dart} (72%) rename learning/tour-of-beam/frontend/lib/components/login/{login_content.dart => content.dart} (87%) rename learning/tour-of-beam/frontend/lib/components/profile/{profile_content.dart => user_menu.dart} (75%) create mode 100644 learning/tour-of-beam/frontend/lib/firebase_options.dart create mode 100644 learning/tour-of-beam/frontend/lib/models/user_progress.dart create mode 100644 learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart create mode 100644 learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit_progress_indicator.dart create mode 100644 learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart rename learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart => playground/frontend/playground_components/lib/src/controllers/public_notifier.dart (63%) diff --git a/learning/tour-of-beam/frontend/lib/auth/method.dart b/learning/tour-of-beam/frontend/lib/auth/method.dart new file mode 100644 index 000000000000..ccc3d63116d9 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/auth/method.dart @@ -0,0 +1,27 @@ +/* + * 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:enum_map/enum_map.dart'; + +part 'method.g.dart'; + +@unmodifiableEnumMap +enum AuthMethod { + google, + github, +} diff --git a/learning/tour-of-beam/frontend/lib/auth/notifier.dart b/learning/tour-of-beam/frontend/lib/auth/notifier.dart new file mode 100644 index 000000000000..a53225589362 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/auth/notifier.dart @@ -0,0 +1,49 @@ +/* + * 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:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'method.dart'; + +class AuthNotifier extends ChangeNotifier { + final _firebase = FirebaseAuth.instance; + final _authProviders = UnmodifiableAuthMethodMap( + google: GoogleAuthProvider(), + github: GithubAuthProvider(), + ); + + AuthNotifier() { + _firebase.authStateChanges().listen((user) async { + notifyListeners(); + }); + } + + bool get isAuthenticated => _firebase.currentUser != null; + + Future get token async => await _firebase.currentUser?.getIdToken(); + + Future logIn(AuthMethod authMethod) async { + await _firebase.signInWithPopup(_authProviders.get(authMethod)); + } + + Future logOut() async { + await _firebase.signOut(); + } +} diff --git a/learning/tour-of-beam/frontend/lib/cache/cache.dart b/learning/tour-of-beam/frontend/lib/cache/cache.dart new file mode 100644 index 000000000000..c061e2fcc181 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/cache/cache.dart @@ -0,0 +1,9 @@ +import 'package:flutter/material.dart'; + +import '../repositories/client/client.dart'; + +abstract class Cache extends ChangeNotifier { + final TobClient client; + + Cache({required this.client}); +} diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart new file mode 100644 index 000000000000..ddda1d9aa770 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart @@ -0,0 +1,69 @@ +/* + * 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:get_it/get_it.dart'; + +import '../auth/notifier.dart'; +import '../models/user_progress.dart'; +import 'cache.dart'; + +class UserProgressCache extends Cache { + final _auth = GetIt.instance.get(); + UserProgressCache({required super.client}) { + _auth.addListener(() { + // TODO(nausharipov): get sdk + updateCompletedUnits('go'); + }); + } + + final _completedUnits = {}; + Future?>? _future; + + Set updateCompletedUnits(String sdkId) { + _future = null; + return getCompletedUnits(sdkId); + } + + Set getCompletedUnits(String sdkId) { + print(['gcu', _future]); + if (_future == null) { + unawaited(_loadCompletedUnits(sdkId)); + } + + return _completedUnits; + } + + Future> _loadCompletedUnits(String sdkId) async { + print(['lcu']); + _future = client.getUserProgress(sdkId); + final result = await _future; + + _completedUnits.clear(); + if (result != null) { + for (final unitProgress in result) { + if (unitProgress.isCompleted) { + _completedUnits.add(unitProgress.id); + } + } + } + notifyListeners(); + return _completedUnits; + } +} diff --git a/learning/tour-of-beam/frontend/lib/components/login/login_button.dart b/learning/tour-of-beam/frontend/lib/components/login/button.dart similarity index 72% rename from learning/tour-of-beam/frontend/lib/components/login/login_button.dart rename to learning/tour-of-beam/frontend/lib/components/login/button.dart index 36d96faffe5a..197699b55402 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/login_button.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/button.dart @@ -20,7 +20,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; -import 'login_content.dart'; +import 'content.dart'; class LoginButton extends StatelessWidget { const LoginButton(); @@ -36,19 +36,22 @@ class LoginButton extends StatelessWidget { } void _openOverlay(BuildContext context) { - OverlayEntry? overlay; - overlay = OverlayEntry( - builder: (context) => DismissibleOverlay( - close: () { - overlay?.remove(); - }, - child: const Positioned( - right: BeamSizes.size10, - top: BeamSizes.appBarHeight, - child: LoginContent(), - ), - ), + final overlayCloser = PublicNotifier(); + final overlay = OverlayEntry( + builder: (context) { + return DismissibleOverlay( + close: overlayCloser.notifyPublic, + child: Positioned( + right: BeamSizes.size10, + top: BeamSizes.appBarHeight, + child: LoginContent( + onLoggedIn: overlayCloser.notifyPublic, + ), + ), + ); + }, ); + overlayCloser.addListener(overlay.remove); Overlay.of(context)?.insert(overlay); } } diff --git a/learning/tour-of-beam/frontend/lib/components/login/login_content.dart b/learning/tour-of-beam/frontend/lib/components/login/content.dart similarity index 87% rename from learning/tour-of-beam/frontend/lib/components/login/login_content.dart rename to learning/tour-of-beam/frontend/lib/components/login/content.dart index d4d0d8873cce..7a73ef1d92ba 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/login_content.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/content.dart @@ -19,18 +19,25 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; +import '../../auth/method.dart'; +import '../../auth/notifier.dart'; import '../../constants/sizes.dart'; import '../../generated/assets.gen.dart'; class LoginContent extends StatelessWidget { - const LoginContent(); + final VoidCallback onLoggedIn; + const LoginContent({ + required this.onLoggedIn, + }); @override Widget build(BuildContext context) { return _Body( child: Column( + mainAxisSize: MainAxisSize.min, children: [ Text( 'ui.signIn', @@ -42,7 +49,9 @@ class LoginContent extends StatelessWidget { textAlign: TextAlign.center, ).tr(), const _Divider(), - const _BrandedLoginButtons(), + _BrandedLoginButtons( + onLoggedIn: onLoggedIn, + ), ], ), ); @@ -82,10 +91,15 @@ class _Divider extends StatelessWidget { } class _BrandedLoginButtons extends StatelessWidget { - const _BrandedLoginButtons(); + final VoidCallback onLoggedIn; + const _BrandedLoginButtons({ + required this.onLoggedIn, + }); @override Widget build(BuildContext context) { + final auth = GetIt.instance.get(); + final isLightTheme = Theme.of(context).brightness == Brightness.light; final textStyle = MaterialStatePropertyAll(Theme.of(context).textTheme.bodyMedium); @@ -129,7 +143,10 @@ class _BrandedLoginButtons extends StatelessWidget { ), const SizedBox(height: BeamSizes.size16), ElevatedButton.icon( - onPressed: () {}, + onPressed: () async { + await auth.logIn(AuthMethod.google); + onLoggedIn(); + }, style: isLightTheme ? googleLightButtonStyle : darkButtonStyle, icon: SvgPicture.asset(Assets.svg.googleLogo), label: const Text('ui.continueGoogle').tr(), diff --git a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart index 959c83876e3c..498b5e2d70af 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart @@ -16,41 +16,52 @@ * limitations under the License. */ +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; import '../../generated/assets.gen.dart'; -import 'profile_content.dart'; +import 'user_menu.dart'; class Avatar extends StatelessWidget { - const Avatar(); + final User user; + const Avatar({required this.user}); @override Widget build(BuildContext context) { + final photoUrl = user.photoURL; return GestureDetector( onTap: () { _openOverlay(context); }, child: CircleAvatar( backgroundColor: BeamColors.white, - foregroundImage: AssetImage(Assets.png.laptopLight.path), + foregroundImage: photoUrl == null + // TODO(nausharipov): placeholder avatar asset + ? AssetImage(Assets.png.laptopLight.path) as ImageProvider + : NetworkImage(photoUrl), ), ); } void _openOverlay(BuildContext context) { + final overlayCloser = PublicNotifier(); OverlayEntry? overlay; overlay = OverlayEntry( - builder: (context) => DismissibleOverlay( - close: () { - overlay?.remove(); - }, - child: const Positioned( - right: BeamSizes.size10, - top: BeamSizes.appBarHeight, - child: ProfileContent(), - ), - ), + builder: (context) { + overlayCloser.addListener(overlay!.remove); + return DismissibleOverlay( + close: overlayCloser.notifyPublic, + child: Positioned( + right: BeamSizes.size10, + top: BeamSizes.appBarHeight, + child: UserMenu( + onLoggedOut: overlayCloser.notifyPublic, + user: user, + ), + ), + ); + }, ); Overlay.of(context)?.insert(overlay); } diff --git a/learning/tour-of-beam/frontend/lib/components/profile/profile_content.dart b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart similarity index 75% rename from learning/tour-of-beam/frontend/lib/components/profile/profile_content.dart rename to learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart index 223f4b0e3845..cbd97a74f6d4 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/profile_content.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart @@ -17,25 +17,36 @@ */ import 'package:easy_localization/easy_localization.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; +import '../../auth/notifier.dart'; import '../../constants/sizes.dart'; import '../../generated/assets.gen.dart'; -class ProfileContent extends StatelessWidget { - const ProfileContent(); +class UserMenu extends StatelessWidget { + final VoidCallback onLoggedOut; + final User user; + + const UserMenu({ + required this.onLoggedOut, + required this.user, + }); @override Widget build(BuildContext context) { return _Body( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - _Info(), - BeamDivider(), - _Buttons(), + children: [ + _Info(user: user), + const BeamDivider(), + _Buttons( + closeOverlay: onLoggedOut, + ), ], ), ); @@ -61,23 +72,32 @@ class _Body extends StatelessWidget { } class _Info extends StatelessWidget { - const _Info(); + final User user; + + const _Info({ + required this.user, + }); @override Widget build(BuildContext context) { + final displayName = user.displayName; + final email = user.email; + return Padding( padding: const EdgeInsets.all(BeamSizes.size16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - 'Name Surname', - style: Theme.of(context).textTheme.titleLarge, - ), - Text( - 'email@mail.com', - style: Theme.of(context).textTheme.bodySmall, - ), + if (displayName != null) + Text( + displayName, + style: Theme.of(context).textTheme.titleLarge, + ), + if (email != null) + Text( + email, + style: Theme.of(context).textTheme.bodySmall, + ), ], ), ); @@ -85,10 +105,15 @@ class _Info extends StatelessWidget { } class _Buttons extends StatelessWidget { - const _Buttons(); + final VoidCallback closeOverlay; + const _Buttons({ + required this.closeOverlay, + }); @override Widget build(BuildContext context) { + final auth = GetIt.instance.get(); + return Column( children: [ _IconLabel( @@ -105,7 +130,10 @@ class _Buttons extends StatelessWidget { ), const BeamDivider(), _IconLabel( - onTap: () {}, + onTap: () async { + await auth.logOut(); + closeOverlay(); + }, iconPath: Assets.svg.profileLogout, label: 'ui.signOut'.tr(), ), @@ -123,7 +151,7 @@ class _Buttons extends StatelessWidget { class _IconLabel extends StatelessWidget { final String iconPath; final String label; - final void Function()? onTap; + final VoidCallback? onTap; // TODO(alexeyinkin): Auto-determine. final bool isSvg; diff --git a/learning/tour-of-beam/frontend/lib/components/scaffold.dart b/learning/tour-of-beam/frontend/lib/components/scaffold.dart index f8352140436e..a1a6329e58d4 100644 --- a/learning/tour-of-beam/frontend/lib/components/scaffold.dart +++ b/learning/tour-of-beam/frontend/lib/components/scaffold.dart @@ -16,11 +16,12 @@ * limitations under the License. */ +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; import 'footer.dart'; -import 'login/login_button.dart'; +import 'login/button.dart'; import 'logo.dart'; import 'profile/avatar.dart'; import 'sdk_dropdown.dart'; @@ -33,9 +34,6 @@ class TobScaffold extends StatelessWidget { required this.child, }); - // TODO(nausharipov): get state - static const _isAuthorized = true; - @override Widget build(BuildContext context) { return Scaffold( @@ -46,9 +44,7 @@ class TobScaffold extends StatelessWidget { SizedBox(width: BeamSizes.size12), _ActionVerticalPadding(child: ToggleThemeButton()), SizedBox(width: BeamSizes.size6), - _ActionVerticalPadding( - child: _isAuthorized ? Avatar() : LoginButton(), - ), + _Profile(), SizedBox(width: BeamSizes.size16), ], ), @@ -62,6 +58,21 @@ class TobScaffold extends StatelessWidget { } } +class _Profile extends StatelessWidget { + const _Profile(); + + @override + Widget build(BuildContext context) { + return _ActionVerticalPadding( + child: StreamBuilder( + stream: FirebaseAuth.instance.userChanges(), + builder: (context, user) => + user.hasData ? Avatar(user: user.data!) : const LoginButton(), + ), + ); + } +} + class _ActionVerticalPadding extends StatelessWidget { final Widget child; diff --git a/learning/tour-of-beam/frontend/lib/config.dart b/learning/tour-of-beam/frontend/lib/config.dart index b7ed542e1b05..7c64c3986b81 100644 --- a/learning/tour-of-beam/frontend/lib/config.dart +++ b/learning/tour-of-beam/frontend/lib/config.dart @@ -18,8 +18,8 @@ // TODO(alexeyinkin): Generate this file on deployment. -const _cloudFunctionsProjectRegion = 'us-central1'; -const _cloudFunctionsProjectId = 'tour-of-beam-2'; +const _cloudFunctionsProjectRegion = 'us-east1'; +const _cloudFunctionsProjectId = 'sandbox-playground-002'; const cloudFunctionsBaseUrl = 'https://' '$_cloudFunctionsProjectRegion-$_cloudFunctionsProjectId' '.cloudfunctions.net'; diff --git a/learning/tour-of-beam/frontend/lib/firebase_options.dart b/learning/tour-of-beam/frontend/lib/firebase_options.dart new file mode 100644 index 000000000000..b3cefabf2d39 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/firebase_options.dart @@ -0,0 +1,63 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + return web; + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for android - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.iOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for ios - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions web = FirebaseOptions( + apiKey: 'AIzaSyD_Nj83s6-EJ_2QxsOzA0W9hULuhwe5FXk', + appId: '1:358160552171:web:39fba96946d1c6c6c12eae', + messagingSenderId: '358160552171', + projectId: 'sandbox-playground-002', + authDomain: 'sandbox-playground-002.firebaseapp.com', + storageBucket: 'sandbox-playground-002.appspot.com', + ); +} diff --git a/learning/tour-of-beam/frontend/lib/locator.dart b/learning/tour-of-beam/frontend/lib/locator.dart index f8146a212e24..95e4fbb8653a 100644 --- a/learning/tour-of-beam/frontend/lib/locator.dart +++ b/learning/tour-of-beam/frontend/lib/locator.dart @@ -19,25 +19,35 @@ import 'package:app_state/app_state.dart'; import 'package:get_it/get_it.dart'; +import 'auth/notifier.dart'; import 'cache/content_tree.dart'; import 'cache/sdk.dart'; import 'cache/unit_content.dart'; +import 'cache/user_progress.dart'; import 'pages/welcome/page.dart'; +import 'repositories/client/client.dart'; import 'repositories/client/cloud_functions_client.dart'; import 'router/page_factory.dart'; import 'router/route_information_parser.dart'; Future initializeServiceLocator() async { + _initializeAuth(); _initializeCaches(); _initializeState(); } +void _initializeAuth() { + GetIt.instance.registerSingleton(AuthNotifier()); +} + void _initializeCaches() { final client = CloudFunctionsTobClient(); + GetIt.instance.registerSingleton(client); GetIt.instance.registerSingleton(ContentTreeCache(client: client)); GetIt.instance.registerSingleton(SdkCache(client: client)); GetIt.instance.registerSingleton(UnitContentCache(client: client)); + GetIt.instance.registerSingleton(UserProgressCache(client: client)); } void _initializeState() { diff --git a/learning/tour-of-beam/frontend/lib/main.dart b/learning/tour-of-beam/frontend/lib/main.dart index 6561ae9f921c..7139c0b42f92 100644 --- a/learning/tour-of-beam/frontend/lib/main.dart +++ b/learning/tour-of-beam/frontend/lib/main.dart @@ -20,16 +20,21 @@ import 'package:app_state/app_state.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization_ext/easy_localization_ext.dart'; import 'package:easy_localization_loader/easy_localization_loader.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; import 'package:provider/provider.dart'; import 'package:url_strategy/url_strategy.dart'; +import 'firebase_options.dart'; import 'locator.dart'; import 'router/route_information_parser.dart'; void main() async { + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); setPathUrlStrategy(); await EasyLocalization.ensureInitialized(); await initializeServiceLocator(); diff --git a/learning/tour-of-beam/frontend/lib/models/user_progress.dart b/learning/tour-of-beam/frontend/lib/models/user_progress.dart new file mode 100644 index 000000000000..b1176820d34f --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/models/user_progress.dart @@ -0,0 +1,35 @@ +/* + * 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:json_annotation/json_annotation.dart'; + +part 'user_progress.g.dart'; + +@JsonSerializable(createToJson: false) +class UserProgressModel { + final String id; + final bool isCompleted; + + const UserProgressModel({ + required this.id, + required this.isCompleted, + }); + + factory UserProgressModel.fromJson(Map json) => + _$UserProgressModelFromJson(json); +} diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart new file mode 100644 index 000000000000..9c1696b6b2bb --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import 'package:flutter/widgets.dart'; +import 'package:get_it/get_it.dart'; + +import '../../../cache/user_progress.dart'; +import '../../../repositories/client/client.dart'; + +class UnitController extends ChangeNotifier { + // TODO(nausharipov): finish + // final String unitId; + // final String sdkId; + + // UnitController({ + // required this.unitId, + // required this.sdkId, + // }); + + Future completeUnit(String sdkId, String unitId) async { + final client = GetIt.instance.get(); + await client.postUnitComplete(sdkId, unitId); + GetIt.instance.get().updateCompletedUnits(sdkId); + } +} diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index ae8fc0e1e706..bc1153fa37fa 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -26,11 +26,13 @@ import '../../config.dart'; import '../../models/unit.dart'; import '../../models/unit_content.dart'; import 'controllers/content_tree.dart'; +import 'controllers/unit.dart'; import 'path.dart'; class TourNotifier extends ChangeNotifier with PageStateMixin { final ContentTreeController contentTreeController; final PlaygroundController playgroundController; + final UnitController unitController; final _unitContentCache = GetIt.instance.get(); UnitContentModel? _currentUnitContent; @@ -41,6 +43,11 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { initialSdkId: initialSdkId, initialTreeIds: initialTreeIds, ), + unitController = UnitController( + // TODO(nausharipov): finish + // unitId: contentTreeController.currentNode.id, + // sdkId: initialSdkId, + ), playgroundController = _createPlaygroundController(initialSdkId) { contentTreeController.addListener(_onChanged); _unitContentCache.addListener(_onChanged); diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart index a45b87f8a2a3..3cce57588047 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart @@ -17,9 +17,12 @@ */ import 'package:easy_localization/easy_localization.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; +import '../../../cache/user_progress.dart'; import '../../../constants/sizes.dart'; import '../state.dart'; import 'unit_content.dart'; @@ -56,7 +59,7 @@ class ContentWidget extends StatelessWidget { ? Container() : UnitContentWidget(unitContent: currentUnitContent), ), - const _ContentFooter(), + _ContentFooter(notifier), ], ); }, @@ -66,7 +69,8 @@ class ContentWidget extends StatelessWidget { } class _ContentFooter extends StatelessWidget { - const _ContentFooter(); + final TourNotifier notifier; + const _ContentFooter(this.notifier); @override Widget build(BuildContext context) { @@ -85,28 +89,65 @@ class _ContentFooter extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - Flexible( - child: OutlinedButton( - style: OutlinedButton.styleFrom( - foregroundColor: themeData.primaryColor, - side: BorderSide(color: themeData.primaryColor), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(BeamSizes.size4), - ), + _CompleteUnitButton(notifier), + ], + ), + ); + } +} + +class _CompleteUnitButton extends StatelessWidget { + final TourNotifier notifier; + const _CompleteUnitButton(this.notifier); + + @override + Widget build(BuildContext context) { + final themeData = Theme.of(context); + final cache = GetIt.instance.get(); + + return AnimatedBuilder( + animation: cache, + builder: (context, child) { + // TODO(nausharipov): finish + // TODO(nausharipov): get sdk + final isDisabled = cache.getCompletedUnits('go').contains( + notifier.contentTreeController.currentNode?.id, + ) || + FirebaseAuth.instance.currentUser == null; + + return Flexible( + child: OutlinedButton( + style: OutlinedButton.styleFrom( + foregroundColor: themeData.primaryColor, + side: BorderSide( + color: isDisabled + ? themeData.disabledColor + : themeData.primaryColor, + ), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(BeamSizes.size4), ), ), - child: const Text( - 'pages.tour.completeUnit', - overflow: TextOverflow.ellipsis, - ).tr(), - onPressed: () { - // TODO(nausharipov): complete unit - }, ), + // TODO(nausharipov): get sdk + onPressed: isDisabled ? null : _completeUnit, + child: const Text( + 'pages.tour.completeUnit', + overflow: TextOverflow.ellipsis, + ).tr(), ), - ], - ), + ); + }, + ); + } + + void _completeUnit() { + // TODO(nausharipov): finish + // TODO(nausharipov): get sdk + notifier.unitController.completeUnit( + 'go', + notifier.contentTreeController.currentNode!.id, ); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart index a25c5498bd92..717288c0dec1 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart @@ -17,11 +17,13 @@ */ import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; -import '../../../generated/assets.gen.dart'; +import '../../../cache/user_progress.dart'; import '../../../models/group.dart'; -import 'tour_progress_indicator.dart'; +import '../../../models/node.dart'; +import 'unit_progress_indicator.dart'; class GroupTitleWidget extends StatelessWidget { final GroupModel group; @@ -38,7 +40,7 @@ class GroupTitleWidget extends StatelessWidget { onTap: onTap, child: Row( children: [ - TourProgressIndicator(assetPath: Assets.svg.unitProgress0), + _GroupProgressIndicator(group: group), Text( group.title, style: Theme.of(context).textTheme.headlineMedium, @@ -48,3 +50,74 @@ class GroupTitleWidget extends StatelessWidget { ); } } + +// TODO(nausharipov): finish +class _GroupProgressIndicator extends StatelessWidget { + final GroupModel group; + const _GroupProgressIndicator({required this.group}); + + @override + Widget build(BuildContext context) { + final cache = GetIt.instance.get(); + + return AnimatedBuilder( + animation: cache, + builder: (context, child) { + final progress = _getGroupProgress( + group.nodes, + // TODO(nausharipov): get once somewhere + // TODO(nausharipov): get sdk + cache.getCompletedUnits('go'), + ); + + if (progress == 1) { + // TODO(nausharipov): finish + return const UnitProgressIndicator( + isCompleted: true, + isSelected: false, + ); + } + + return Container( + margin: const EdgeInsets.symmetric( + horizontal: BeamSizes.size6, + ), + height: BeamSizes.size8, + width: BeamSizes.size8, + child: CircularProgressIndicator( + strokeWidth: BeamSizes.size3, + color: BeamColors.green, + backgroundColor: Theme.of(context) + .extension()! + .unselectedProgressColor, + value: progress, + ), + ); + }, + ); + } + + double _getGroupProgress( + List groupNodes, + Set completedUnits, + ) { + var completed = 0; + var total = 0; + + void countNodes(List nodes) { + for (final node in nodes) { + if (node is GroupModel) { + countNodes(node.nodes); + } else { + total += 1; + if (completedUnits.contains(node.id)) { + completed += 1; + } + } + } + } + + countNodes(groupNodes); + return completed / total; + } +} diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart index 914361a347a4..acc77f79acc7 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart @@ -17,12 +17,13 @@ */ import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; -import '../../../generated/assets.gen.dart'; +import '../../../cache/user_progress.dart'; import '../../../models/unit.dart'; import '../controllers/content_tree.dart'; -import 'tour_progress_indicator.dart'; +import 'unit_progress_indicator.dart'; class UnitWidget extends StatelessWidget { final UnitModel unit; @@ -35,15 +36,39 @@ class UnitWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return ClickableWidget( - onTap: () => contentTreeController.onNodeTap(unit), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: BeamSizes.size10), - child: Row( - children: [ - TourProgressIndicator(assetPath: Assets.svg.unitProgress0), - Expanded(child: Text(unit.title)), - ], + final cache = GetIt.instance.get(); + + return AnimatedBuilder( + animation: contentTreeController, + builder: (context, child) { + final isSelected = contentTreeController.currentNode?.id == unit.id; + // TODO(nausharipov): get sdk + final isCompleted = cache.getCompletedUnits('go').contains(unit.id); + + return ClickableWidget( + onTap: () => contentTreeController.openNode(unit), + child: Container( + decoration: BoxDecoration( + color: isSelected ? Theme.of(context).selectedRowColor : null, + borderRadius: BorderRadius.circular(BeamSizes.size3), + ), + padding: const EdgeInsets.symmetric(vertical: BeamSizes.size10), + child: Row( + children: [ + // TODO(nausharipov): finish + AnimatedBuilder( + animation: cache, + builder: (context, child) => UnitProgressIndicator( + isCompleted: isCompleted, + isSelected: isSelected, + ), + ), + Expanded( + child: Text(unit.title), + ), + ], + ), + ), ), ), ); diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit_progress_indicator.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit_progress_indicator.dart new file mode 100644 index 000000000000..5671cd70beb1 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit_progress_indicator.dart @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:playground_components/playground_components.dart'; + +import '../../../generated/assets.gen.dart'; + +class UnitProgressIndicator extends StatelessWidget { + final bool isCompleted; + final bool isSelected; + + const UnitProgressIndicator({ + required this.isCompleted, + required this.isSelected, + }); + + @override + Widget build(BuildContext context) { + final ext = Theme.of(context).extension()!; + final Color color; + if (isCompleted) { + color = BeamColors.green; + } else if (isSelected) { + color = ext.selectedProgressColor; + } else { + color = ext.unselectedProgressColor; + } + + return Padding( + padding: const EdgeInsets.only( + left: BeamSizes.size4, + right: BeamSizes.size8, + ), + child: SvgPicture.asset( + isCompleted ? Assets.svg.unitProgress100 : Assets.svg.unitProgress0, + color: color, + ), + ); + } +} diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart index 421593562672..0204aaa60701 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart @@ -20,11 +20,13 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; +import '../../auth/notifier.dart'; import '../../components/builders/content_tree.dart'; import '../../components/builders/sdks.dart'; -import '../../components/filler_text.dart'; +import '../../components/login/content.dart'; import '../../components/scaffold.dart'; import '../../constants/sizes.dart'; import '../../generated/assets.gen.dart'; @@ -212,13 +214,32 @@ class _IntroText extends StatelessWidget { color: BeamColors.grey2, constraints: const BoxConstraints(maxWidth: _dividerMaxWidth), ), - RichText( - text: TextSpan( - style: Theme.of(context).textTheme.bodyLarge, - children: [ + const _IntroTextBody(), + ], + ); + } +} + +class _IntroTextBody extends StatelessWidget { + const _IntroTextBody(); + + @override + Widget build(BuildContext context) { + final auth = GetIt.instance.get(); + return AnimatedBuilder( + animation: auth, + builder: (context, child) => RichText( + text: TextSpan( + style: Theme.of(context).textTheme.bodyLarge, + children: [ + TextSpan( + text: 'pages.welcome.ifSaveProgress'.tr(), + ), + if (auth.isAuthenticated) TextSpan( - text: 'pages.welcome.ifSaveProgress'.tr(), - ), + text: 'pages.welcome.signIn'.tr(), + ) + else TextSpan( text: 'pages.welcome.signIn'.tr(), style: Theme.of(context) @@ -227,14 +248,26 @@ class _IntroText extends StatelessWidget { .copyWith(color: Theme.of(context).primaryColor), recognizer: TapGestureRecognizer() ..onTap = () { - // TODO(nausharipov): sign in + _openLoginDialog(context); }, ), - TextSpan(text: '\n\n${'pages.welcome.selectLanguage'.tr()}'), - ], - ), + TextSpan(text: '\n\n${'pages.welcome.selectLanguage'.tr()}'), + ], ), - ], + ), + ); + } + + void _openLoginDialog(BuildContext context) { + showDialog( + context: context, + builder: (context) => Dialog( + child: LoginContent( + onLoggedIn: () { + Navigator.pop(context); + }, + ), + ), ); } } diff --git a/learning/tour-of-beam/frontend/lib/repositories/client/client.dart b/learning/tour-of-beam/frontend/lib/repositories/client/client.dart index bdeb3214316c..45980af1a81c 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/client/client.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/client/client.dart @@ -18,6 +18,7 @@ import '../../models/content_tree.dart'; import '../../models/unit_content.dart'; +import '../../models/user_progress.dart'; import '../models/get_sdks_response.dart'; abstract class TobClient { @@ -26,4 +27,8 @@ abstract class TobClient { Future getSdks(); Future getUnitContent(String sdkId, String unitId); + + Future?> getUserProgress(String sdkId); + + Future postUnitComplete(String sdkId, String id); } diff --git a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart index e7029fcd829d..02472ada6cb7 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart @@ -17,16 +17,22 @@ */ import 'dart:convert'; +import 'dart:io'; +import 'package:get_it/get_it.dart'; import 'package:http/http.dart' as http; +import '../../auth/notifier.dart'; import '../../config.dart'; import '../../models/content_tree.dart'; import '../../models/unit_content.dart'; +import '../../models/user_progress.dart'; import '../models/get_content_tree_response.dart'; import '../models/get_sdks_response.dart'; +import '../models/get_user_progress_response.dart'; import 'client.dart'; +// TODO(nausharipov): add an abstraction layer for calling API methods class CloudFunctionsTobClient extends TobClient { @override Future getSdks() async { @@ -42,6 +48,7 @@ class CloudFunctionsTobClient extends TobClient { @override Future getContentTree(String sdkId) async { + // TODO(nausharipov): finish final json = await http.get( Uri.parse( '$cloudFunctionsBaseUrl/getContentTree?sdk=$sdkId', @@ -64,4 +71,39 @@ class CloudFunctionsTobClient extends TobClient { final map = jsonDecode(utf8.decode(json.bodyBytes)) as Map; return UnitContentModel.fromJson(map); } + + @override + Future?> getUserProgress(String sdkId) async { + // TODO(nausharipov): check auth + final token = await GetIt.instance.get().token; + if (token == null) { + return null; + } + final json = await http.get( + Uri.parse( + '$cloudFunctionsBaseUrl/getUserProgress?sdk=$sdkId', + ), + headers: { + HttpHeaders.authorizationHeader: 'Bearer $token', + }, + ); + print(['gup', json]); + final map = jsonDecode(utf8.decode(json.bodyBytes)) as Map; + final response = GetUserProgressResponse.fromJson(map); + return response.units; + } + + @override + Future postUnitComplete(String sdkId, String id) async { + final token = await GetIt.instance.get().token; + final json = await http.post( + Uri.parse( + '$cloudFunctionsBaseUrl/postUnitComplete?sdk=$sdkId&id=$id', + ), + headers: { + HttpHeaders.authorizationHeader: 'Bearer $token', + }, + ); + final map = jsonDecode(utf8.decode(json.bodyBytes)); + } } diff --git a/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart b/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart new file mode 100644 index 000000000000..8328c99fb9d4 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart @@ -0,0 +1,33 @@ +/* + * 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:json_annotation/json_annotation.dart'; + +import '../../models/user_progress.dart'; + +part 'get_user_progress_response.g.dart'; + +@JsonSerializable(createToJson: false) +class GetUserProgressResponse { + final List units; + + const GetUserProgressResponse({required this.units}); + + factory GetUserProgressResponse.fromJson(Map json) => + _$GetUserProgressResponseFromJson(json); +} diff --git a/learning/tour-of-beam/frontend/pubspec.lock b/learning/tour-of-beam/frontend/pubspec.lock index 9983b9bb5304..01ec30353878 100644 --- a/learning/tour-of-beam/frontend/pubspec.lock +++ b/learning/tour-of-beam/frontend/pubspec.lock @@ -8,6 +8,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "46.0.0" + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.7" aligned_dialog: dependency: transitive description: @@ -148,6 +155,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.1" + cloud_firestore_platform_interface: + dependency: transitive + description: + name: cloud_firestore_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "5.8.4" + cloud_firestore_web: + dependency: transitive + description: + name: cloud_firestore_web + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.4" code_builder: dependency: transitive description: @@ -232,6 +253,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.0.2" + enum_map: + dependency: "direct main" + description: + name: enum_map + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" + enum_map_gen: + dependency: "direct dev" + description: + name: enum_map_gen + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" equatable: dependency: "direct dev" description: @@ -260,6 +295,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" + firebase_auth: + dependency: "direct main" + description: + name: firebase_auth + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.1" + firebase_auth_platform_interface: + dependency: transitive + description: + name: firebase_auth_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "6.11.1" + firebase_auth_web: + dependency: transitive + description: + name: firebase_auth_web + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "4.5.2" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" fixnum: dependency: transitive description: @@ -278,7 +355,7 @@ packages: name: flutter_code_editor url: "https://pub.dartlang.org" source: hosted - version: "0.1.1" + version: "0.1.3" flutter_driver: dependency: transitive description: flutter @@ -324,6 +401,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.12" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.0" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.2" flutter_svg: dependency: "direct main" description: @@ -374,6 +493,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" + google_sign_in: + dependency: "direct main" + description: + name: google_sign_in + url: "https://pub.dartlang.org" + source: hosted + version: "5.4.2" + google_sign_in_android: + dependency: transitive + description: + name: google_sign_in_android + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.1" + google_sign_in_ios: + dependency: transitive + description: + name: google_sign_in_ios + url: "https://pub.dartlang.org" + source: hosted + version: "5.5.0" + google_sign_in_platform_interface: + dependency: transitive + description: + name: google_sign_in_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + google_sign_in_web: + dependency: transitive + description: + name: google_sign_in_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.2" googleapis_auth: dependency: transitive description: @@ -637,7 +791,7 @@ packages: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" pool: dependency: transitive description: @@ -680,6 +834,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.1" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" rxdart: dependency: transitive description: diff --git a/learning/tour-of-beam/frontend/pubspec.yaml b/learning/tour-of-beam/frontend/pubspec.yaml index a6e829542e0c..19179442725b 100644 --- a/learning/tour-of-beam/frontend/pubspec.yaml +++ b/learning/tour-of-beam/frontend/pubspec.yaml @@ -31,11 +31,16 @@ dependencies: easy_localization: ^3.0.1 easy_localization_ext: ^0.1.0 easy_localization_loader: ^1.0.0 + enum_map: ^0.2.1 + firebase_auth: ^4.1.1 + firebase_core: ^2.1.1 flutter: { sdk: flutter } flutter_markdown: ^0.6.12 + flutter_secure_storage: ^6.0.0 flutter_svg: ^1.0.3 get_it: ^7.2.0 google_fonts: ^3.0.1 + google_sign_in: ^5.4.2 http: ^0.13.5 json_annotation: ^4.7.0 markdown: ^6.0.1 @@ -47,6 +52,7 @@ dependencies: dev_dependencies: build_runner: ^2.2.0 + enum_map_gen: ^0.2.0 equatable: ^2.0.5 flutter_gen_runner: ^4.3.0 flutter_test: { sdk: flutter } diff --git a/playground/frontend/playground_components/lib/playground_components.dart b/playground/frontend/playground_components/lib/playground_components.dart index 24837c8fc0bd..dd3a726a9260 100644 --- a/playground/frontend/playground_components/lib/playground_components.dart +++ b/playground/frontend/playground_components/lib/playground_components.dart @@ -25,6 +25,7 @@ export 'src/constants/sizes.dart'; export 'src/controllers/example_loaders/examples_loader.dart'; export 'src/controllers/playground_controller.dart'; +export 'src/controllers/public_notifier.dart'; export 'src/enums/complexity.dart'; diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart b/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart similarity index 63% rename from learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart rename to playground/frontend/playground_components/lib/src/controllers/public_notifier.dart index 6184a22a9d4f..5744d304da8b 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart +++ b/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart @@ -17,22 +17,7 @@ */ import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:playground_components/playground_components.dart'; -class TourProgressIndicator extends StatelessWidget { - final String assetPath; - - const TourProgressIndicator({required this.assetPath}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only( - left: BeamSizes.size4, - right: BeamSizes.size8, - ), - child: SvgPicture.asset(assetPath), - ); - } +class PublicNotifier extends ChangeNotifier { + void notifyPublic() => notifyListeners(); } From 12a685d1f00140981c8241a2477b5ee0707e47be Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 18 Nov 2022 19:36:34 +0600 Subject: [PATCH 17/65] unit file fix --- .../frontend/lib/pages/tour/widgets/unit.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart index acc77f79acc7..a316f991c3f4 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart @@ -42,8 +42,6 @@ class UnitWidget extends StatelessWidget { animation: contentTreeController, builder: (context, child) { final isSelected = contentTreeController.currentNode?.id == unit.id; - // TODO(nausharipov): get sdk - final isCompleted = cache.getCompletedUnits('go').contains(unit.id); return ClickableWidget( onTap: () => contentTreeController.openNode(unit), @@ -59,7 +57,9 @@ class UnitWidget extends StatelessWidget { AnimatedBuilder( animation: cache, builder: (context, child) => UnitProgressIndicator( - isCompleted: isCompleted, + // TODO(nausharipov): get sdk + isCompleted: + cache.getCompletedUnits('go').contains(unit.id), isSelected: isSelected, ), ), @@ -69,8 +69,8 @@ class UnitWidget extends StatelessWidget { ], ), ), - ), - ), + ); + }, ); } } From de0f7c34f2a686f22137c464d8815a5f6c2cb9c4 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 18 Nov 2022 20:00:17 +0600 Subject: [PATCH 18/65] sdk selection works with auth --- .../frontend/lib/cache/user_progress.dart | 14 +- .../frontend/lib/components/scaffold.dart | 4 +- .../frontend/lib/constants/storage_keys.dart | 7 - .../tour-of-beam/frontend/lib/locator.dart | 2 +- .../lib/pages/tour/widgets/content.dart | 11 +- .../lib/pages/tour/widgets/group_title.dart | 66 +- .../frontend/lib/pages/tour/widgets/unit.dart | 16 +- .../lib/src/controllers/public_notifier.dart | 5 - .../playground_components/pubspec.lock | 941 ++++++++++++++++++ 9 files changed, 1004 insertions(+), 62 deletions(-) create mode 100644 playground/frontend/playground_components/pubspec.lock diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart index ddda1d9aa770..e4541f316518 100644 --- a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart @@ -22,20 +22,26 @@ import 'package:get_it/get_it.dart'; import '../auth/notifier.dart'; import '../models/user_progress.dart'; +import '../state.dart'; import 'cache.dart'; class UserProgressCache extends Cache { + final _app = GetIt.instance.get(); final _auth = GetIt.instance.get(); UserProgressCache({required super.client}) { - _auth.addListener(() { - // TODO(nausharipov): get sdk - updateCompletedUnits('go'); - }); + _auth.addListener(_onChanged); + _app.addListener(_onChanged); } final _completedUnits = {}; Future?>? _future; + void _onChanged() { + if (_app.sdkId != null) { + updateCompletedUnits(_app.sdkId!); + } + } + Set updateCompletedUnits(String sdkId) { _future = null; return getCompletedUnits(sdkId); diff --git a/learning/tour-of-beam/frontend/lib/components/scaffold.dart b/learning/tour-of-beam/frontend/lib/components/scaffold.dart index e04b8df8272e..782429354ab5 100644 --- a/learning/tour-of-beam/frontend/lib/components/scaffold.dart +++ b/learning/tour-of-beam/frontend/lib/components/scaffold.dart @@ -49,9 +49,7 @@ class TobScaffold extends StatelessWidget { const SizedBox(width: BeamSizes.size12), const _ActionVerticalPadding(child: ToggleThemeButton()), const SizedBox(width: BeamSizes.size6), - const _ActionVerticalPadding( - child: _isAuthorized ? Avatar() : LoginButton(), - ), + const _Profile(), const SizedBox(width: BeamSizes.size16), ], ), diff --git a/learning/tour-of-beam/frontend/lib/constants/storage_keys.dart b/learning/tour-of-beam/frontend/lib/constants/storage_keys.dart index 36a0a26febaf..84b289e115e8 100644 --- a/learning/tour-of-beam/frontend/lib/constants/storage_keys.dart +++ b/learning/tour-of-beam/frontend/lib/constants/storage_keys.dart @@ -16,13 +16,6 @@ * limitations under the License. */ -<<<<<<<< HEAD:playground/frontend/playground_components/lib/src/controllers/public_notifier.dart -import 'package:flutter/material.dart'; - -class PublicNotifier extends ChangeNotifier { - void notifyPublic() => notifyListeners(); -======== class StorageKeys { static const sdkId = 'sdkId'; ->>>>>>>> origin/tour-header-sdk-selector:learning/tour-of-beam/frontend/lib/constants/storage_keys.dart } diff --git a/learning/tour-of-beam/frontend/lib/locator.dart b/learning/tour-of-beam/frontend/lib/locator.dart index 27ca813ed641..9d580321fc1d 100644 --- a/learning/tour-of-beam/frontend/lib/locator.dart +++ b/learning/tour-of-beam/frontend/lib/locator.dart @@ -33,8 +33,8 @@ import 'state.dart'; Future initializeServiceLocator() async { _initializeAuth(); - _initializeCaches(); _initializeState(); + _initializeCaches(); } void _initializeAuth() { diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart index 3cce57588047..80f7860bfbd2 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart @@ -24,6 +24,7 @@ import 'package:playground_components/playground_components.dart'; import '../../../cache/user_progress.dart'; import '../../../constants/sizes.dart'; +import '../../../state.dart'; import '../state.dart'; import 'unit_content.dart'; @@ -104,13 +105,13 @@ class _CompleteUnitButton extends StatelessWidget { Widget build(BuildContext context) { final themeData = Theme.of(context); final cache = GetIt.instance.get(); + final app = GetIt.instance.get(); return AnimatedBuilder( animation: cache, builder: (context, child) { // TODO(nausharipov): finish - // TODO(nausharipov): get sdk - final isDisabled = cache.getCompletedUnits('go').contains( + final isDisabled = cache.getCompletedUnits(app.sdkId!).contains( notifier.contentTreeController.currentNode?.id, ) || FirebaseAuth.instance.currentUser == null; @@ -130,7 +131,6 @@ class _CompleteUnitButton extends StatelessWidget { ), ), ), - // TODO(nausharipov): get sdk onPressed: isDisabled ? null : _completeUnit, child: const Text( 'pages.tour.completeUnit', @@ -144,9 +144,10 @@ class _CompleteUnitButton extends StatelessWidget { void _completeUnit() { // TODO(nausharipov): finish - // TODO(nausharipov): get sdk + final app = GetIt.instance.get(); + notifier.unitController.completeUnit( - 'go', + app.sdkId!, notifier.contentTreeController.currentNode!.id, ); } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart index 717288c0dec1..5fb1833555cf 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart @@ -23,6 +23,7 @@ import 'package:playground_components/playground_components.dart'; import '../../../cache/user_progress.dart'; import '../../../models/group.dart'; import '../../../models/node.dart'; +import '../../../state.dart'; import 'unit_progress_indicator.dart'; class GroupTitleWidget extends StatelessWidget { @@ -59,41 +60,44 @@ class _GroupProgressIndicator extends StatelessWidget { @override Widget build(BuildContext context) { final cache = GetIt.instance.get(); + final app = GetIt.instance.get(); return AnimatedBuilder( - animation: cache, - builder: (context, child) { - final progress = _getGroupProgress( - group.nodes, - // TODO(nausharipov): get once somewhere - // TODO(nausharipov): get sdk - cache.getCompletedUnits('go'), - ); - - if (progress == 1) { - // TODO(nausharipov): finish - return const UnitProgressIndicator( - isCompleted: true, - isSelected: false, + animation: app, + builder: (context, child) => AnimatedBuilder( + animation: cache, + builder: (context, child) { + final progress = _getGroupProgress( + group.nodes, + // TODO(nausharipov): get once somewhere + cache.getCompletedUnits(app.sdkId!), ); - } - return Container( - margin: const EdgeInsets.symmetric( - horizontal: BeamSizes.size6, - ), - height: BeamSizes.size8, - width: BeamSizes.size8, - child: CircularProgressIndicator( - strokeWidth: BeamSizes.size3, - color: BeamColors.green, - backgroundColor: Theme.of(context) - .extension()! - .unselectedProgressColor, - value: progress, - ), - ); - }, + if (progress == 1) { + // TODO(nausharipov): finish + return const UnitProgressIndicator( + isCompleted: true, + isSelected: false, + ); + } + + return Container( + margin: const EdgeInsets.symmetric( + horizontal: BeamSizes.size6, + ), + height: BeamSizes.size8, + width: BeamSizes.size8, + child: CircularProgressIndicator( + strokeWidth: BeamSizes.size3, + color: BeamColors.green, + backgroundColor: Theme.of(context) + .extension()! + .unselectedProgressColor, + value: progress, + ), + ); + }, + ), ); } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart index a316f991c3f4..085012406eec 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart @@ -22,6 +22,7 @@ import 'package:playground_components/playground_components.dart'; import '../../../cache/user_progress.dart'; import '../../../models/unit.dart'; +import '../../../state.dart'; import '../controllers/content_tree.dart'; import 'unit_progress_indicator.dart'; @@ -37,6 +38,7 @@ class UnitWidget extends StatelessWidget { @override Widget build(BuildContext context) { final cache = GetIt.instance.get(); + final app = GetIt.instance.get(); return AnimatedBuilder( animation: contentTreeController, @@ -55,12 +57,14 @@ class UnitWidget extends StatelessWidget { children: [ // TODO(nausharipov): finish AnimatedBuilder( - animation: cache, - builder: (context, child) => UnitProgressIndicator( - // TODO(nausharipov): get sdk - isCompleted: - cache.getCompletedUnits('go').contains(unit.id), - isSelected: isSelected, + animation: app, + builder: (context, child) => AnimatedBuilder( + animation: cache, + builder: (context, child) => UnitProgressIndicator( + isCompleted: + cache.getCompletedUnits(app.sdkId!).contains(unit.id), + isSelected: isSelected, + ), ), ), Expanded( diff --git a/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart b/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart index 36a0a26febaf..5744d304da8b 100644 --- a/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart +++ b/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart @@ -16,13 +16,8 @@ * limitations under the License. */ -<<<<<<<< HEAD:playground/frontend/playground_components/lib/src/controllers/public_notifier.dart import 'package:flutter/material.dart'; class PublicNotifier extends ChangeNotifier { void notifyPublic() => notifyListeners(); -======== -class StorageKeys { - static const sdkId = 'sdkId'; ->>>>>>>> origin/tour-header-sdk-selector:learning/tour-of-beam/frontend/lib/constants/storage_keys.dart } diff --git a/playground/frontend/playground_components/pubspec.lock b/playground/frontend/playground_components/pubspec.lock new file mode 100644 index 000000000000..31dfaefb36a0 --- /dev/null +++ b/playground/frontend/playground_components/pubspec.lock @@ -0,0 +1,941 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "47.0.0" + aligned_dialog: + dependency: "direct main" + description: + name: aligned_dialog + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.6" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "4.7.0" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.4" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.9.0" + autotrie: + dependency: transitive + description: + name: autotrie + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.10" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.2" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.2.7" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.4.2" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.3.0" + collection: + dependency: "direct main" + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.16.0" + color: + dependency: transitive + description: + name: color + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + connectivity_plus: + dependency: transitive + description: + name: connectivity_plus + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.9" + connectivity_plus_linux: + dependency: transitive + description: + name: connectivity_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + connectivity_plus_macos: + dependency: transitive + description: + name: connectivity_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.6" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.3" + connectivity_plus_web: + dependency: transitive + description: + name: connectivity_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.5" + connectivity_plus_windows: + dependency: transitive + description: + name: connectivity_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.2" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" + csv: + dependency: transitive + description: + name: csv + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.1" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.4" + dartx: + dependency: transitive + description: + name: dartx + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + dbus: + dependency: transitive + description: + name: dbus + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.8" + easy_localization: + dependency: "direct main" + description: + name: easy_localization + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + easy_localization_ext: + dependency: "direct main" + description: + name: easy_localization_ext + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.1" + easy_localization_loader: + dependency: "direct main" + description: + name: easy_localization_loader + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1+1" + easy_logger: + dependency: transitive + description: + name: easy_logger + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.2" + equatable: + dependency: "direct main" + description: + name: equatable + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.4" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_code_editor: + dependency: "direct main" + description: + name: flutter_code_editor + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.8" + flutter_gen_core: + dependency: transitive + description: + name: flutter_gen_core + url: "https://pub.dartlang.org" + source: hosted + version: "4.3.0" + flutter_gen_runner: + dependency: "direct dev" + description: + name: flutter_gen_runner + url: "https://pub.dartlang.org" + source: hosted + version: "4.3.0" + flutter_highlight: + dependency: transitive + description: + name: flutter_highlight + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.0" + flutter_localizations: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_markdown: + dependency: "direct main" + description: + name: flutter_markdown + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.13" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.6" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + googleapis_auth: + dependency: transitive + description: + name: googleapis_auth + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + grpc: + dependency: "direct main" + description: + name: grpc + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + highlight: + dependency: "direct main" + description: + name: highlight + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.0" + hive: + dependency: transitive + description: + name: hive + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.3" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.5" + http2: + dependency: transitive + description: + name: http2 + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.2" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.4" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.7.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + url: "https://pub.dartlang.org" + source: hosted + version: "6.5.4" + linked_scroll_controller: + dependency: transitive + description: + name: linked_scroll_controller + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + markdown: + dependency: transitive + description: + name: markdown + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.12" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.5" + meta: + dependency: "direct main" + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + mockito: + dependency: "direct dev" + description: + name: mockito + url: "https://pub.dartlang.org" + source: hosted + version: "5.2.0" + nested: + dependency: transitive + description: + name: nested + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.0" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.2" + path_drawing: + dependency: transitive + description: + name: path_drawing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + path_provider: + dependency: transitive + description: + name: path_provider + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.21" + path_provider_ios: + dependency: transitive + description: + name: path_provider_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.7" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.6" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.0" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.2" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.1" + process: + dependency: transitive + description: + name: process + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.4" + protobuf: + dependency: "direct main" + description: + name: protobuf + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + provider: + dependency: "direct main" + description: + name: provider + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.4" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + scrollable_positioned_list: + dependency: transitive + description: + name: scrollable_positioned_list + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.15" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.14" + shared_preferences_ios: + dependency: transitive + description: + name: shared_preferences_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.4.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.6" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.3" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.9.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.12" + time: + dependency: transitive + description: + name: time + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + total_lints: + dependency: "direct dev" + description: + name: total_lints + url: "https://pub.dartlang.org" + source: hosted + version: "2.18.0" + tuple: + dependency: transitive + description: + name: tuple + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + win32: + dependency: transitive + description: + name: win32 + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0+2" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.0" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" +sdks: + dart: ">=2.18.1 <3.0.0" + flutter: ">=3.3.2" From 3a10e8d7633bb4d6d9bd39ba5515aacae6208554 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 18 Nov 2022 20:48:13 +0600 Subject: [PATCH 19/65] show sdk selector in welcome screen --- learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart index 8f24d4629cfb..c3d169c42785 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart @@ -44,7 +44,7 @@ class WelcomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return TobScaffold( - showSdkSelector: false, + showSdkSelector: true, child: SingleChildScrollView( child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns ? _WideWelcome(notifier) From de273baf06cc76e4da1f94064131f0093e265f0c Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 18 Nov 2022 20:51:31 +0600 Subject: [PATCH 20/65] hide back button after navigating from welcome --- learning/tour-of-beam/frontend/lib/components/scaffold.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/learning/tour-of-beam/frontend/lib/components/scaffold.dart b/learning/tour-of-beam/frontend/lib/components/scaffold.dart index 782429354ab5..3bb6f5948360 100644 --- a/learning/tour-of-beam/frontend/lib/components/scaffold.dart +++ b/learning/tour-of-beam/frontend/lib/components/scaffold.dart @@ -42,6 +42,7 @@ class TobScaffold extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( + automaticallyImplyLeading: false, title: const Logo(), actions: [ if (showSdkSelector) From 70c0d61d3a96e120d312f1aecc6a38e73e551697 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Sat, 19 Nov 2022 20:46:18 +0600 Subject: [PATCH 21/65] comments (0) --- .../frontend/lib/components/sdk_dropdown.dart | 2 +- .../frontend/lib/pages/tour/state.dart | 6 +-- .../frontend/lib/pages/welcome/screen.dart | 4 +- learning/tour-of-beam/frontend/lib/state.dart | 20 +++++---- learning/tour-of-beam/frontend/pubspec.lock | 42 ------------------- learning/tour-of-beam/frontend/pubspec.yaml | 1 - 6 files changed, 17 insertions(+), 58 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart index dd65f020da20..15c8cbdea97d 100644 --- a/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart +++ b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart @@ -23,7 +23,7 @@ import 'builders/sdks.dart'; class SdkDropdown extends StatelessWidget { final String sdkId; - final void Function(String? sdkId) onChanged; + final ValueChanged onChanged; const SdkDropdown({ required this.sdkId, required this.onChanged, diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 8184a19df9f5..37c1f6c8304b 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -46,7 +46,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { playgroundController = _createPlaygroundController(initialSdkId) { contentTreeController.addListener(_onChanged); _unitContentCache.addListener(_onChanged); - _appNotifier.addListener(_setSdk); + _appNotifier.addListener(_onAppNotifierChanged); _onChanged(); } @@ -56,7 +56,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { treeIds: contentTreeController.treeIds, ); - void _setSdk() { + void _onAppNotifierChanged() { final sdkId = _appNotifier.sdkId; if (sdkId != null) { playgroundController.setSdk(Sdk.parseOrCreate(sdkId)); @@ -163,7 +163,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { void dispose() { _unitContentCache.removeListener(_onChanged); contentTreeController.removeListener(_onChanged); - _appNotifier.removeListener(_setSdk); + _appNotifier.removeListener(_onAppNotifierChanged); super.dispose(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart index 0adf9a0f49f3..9d33f3fa0871 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart @@ -137,7 +137,7 @@ class _SdkSelection extends StatelessWidget { sdkId: appNotifier.sdkId, setSdkId: (v) => appNotifier.sdkId = v, onStartPressed: () { - startTour(appNotifier.sdkId); + _startTour(appNotifier.sdkId); }, ), ); @@ -151,7 +151,7 @@ class _SdkSelection extends StatelessWidget { ); } - void startTour(String? sdkId) { + void _startTour(String? sdkId) { if (sdkId == null) { return; } diff --git a/learning/tour-of-beam/frontend/lib/state.dart b/learning/tour-of-beam/frontend/lib/state.dart index 250ebc0c2558..df87c21838d7 100644 --- a/learning/tour-of-beam/frontend/lib/state.dart +++ b/learning/tour-of-beam/frontend/lib/state.dart @@ -19,12 +19,11 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'constants/storage_keys.dart'; class AppNotifier extends ChangeNotifier { - static const _storage = FlutterSecureStorage(); String? _sdkId; AppNotifier() { @@ -35,19 +34,22 @@ class AppNotifier extends ChangeNotifier { set sdkId(String? newValue) { _sdkId = newValue; - unawaited(_writeSdkId()); + unawaited(_writeSdkId(newValue)); notifyListeners(); } - Future _writeSdkId() async { - await _storage.write( - key: StorageKeys.sdkId, - value: _sdkId, - ); + Future _writeSdkId(String? value) async { + final preferences = await SharedPreferences.getInstance(); + if (value != null) { + await preferences.setString(StorageKeys.sdkId, value); + } else { + await preferences.remove(StorageKeys.sdkId); + } } Future _readSdkId() async { - _sdkId = await _storage.read(key: StorageKeys.sdkId); + final preferences = await SharedPreferences.getInstance(); + _sdkId = preferences.getString(StorageKeys.sdkId); notifyListeners(); } } diff --git a/learning/tour-of-beam/frontend/pubspec.lock b/learning/tour-of-beam/frontend/pubspec.lock index 9fd4f59c25c5..6b49ce6e37bc 100644 --- a/learning/tour-of-beam/frontend/pubspec.lock +++ b/learning/tour-of-beam/frontend/pubspec.lock @@ -324,48 +324,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.12" - flutter_secure_storage: - dependency: "direct main" - description: - name: flutter_secure_storage - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.0" - flutter_secure_storage_linux: - dependency: transitive - description: - name: flutter_secure_storage_linux - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - flutter_secure_storage_macos: - dependency: transitive - description: - name: flutter_secure_storage_macos - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - flutter_secure_storage_platform_interface: - dependency: transitive - description: - name: flutter_secure_storage_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - flutter_secure_storage_web: - dependency: transitive - description: - name: flutter_secure_storage_web - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - flutter_secure_storage_windows: - dependency: transitive - description: - name: flutter_secure_storage_windows - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.2" flutter_svg: dependency: "direct main" description: diff --git a/learning/tour-of-beam/frontend/pubspec.yaml b/learning/tour-of-beam/frontend/pubspec.yaml index 86cc96ce4754..a8f4fd9a4ce7 100644 --- a/learning/tour-of-beam/frontend/pubspec.yaml +++ b/learning/tour-of-beam/frontend/pubspec.yaml @@ -34,7 +34,6 @@ dependencies: easy_localization_loader: ^1.0.0 flutter: { sdk: flutter } flutter_markdown: ^0.6.12 - flutter_secure_storage: ^6.0.0 flutter_svg: ^1.0.3 get_it: ^7.2.0 google_fonts: ^3.0.1 From 6f53e30d39ba793850153a2a6077fbe6bbab2b51 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 21 Nov 2022 16:04:31 +0600 Subject: [PATCH 22/65] cache license --- .../tour-of-beam/frontend/lib/cache/cache.dart | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/learning/tour-of-beam/frontend/lib/cache/cache.dart b/learning/tour-of-beam/frontend/lib/cache/cache.dart index c061e2fcc181..a77876d27023 100644 --- a/learning/tour-of-beam/frontend/lib/cache/cache.dart +++ b/learning/tour-of-beam/frontend/lib/cache/cache.dart @@ -1,3 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import 'package:flutter/material.dart'; import '../repositories/client/client.dart'; From 5ad067f7ccdb976fcdb26102d983bea936a9ba83 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 21 Nov 2022 17:55:38 +0600 Subject: [PATCH 23/65] non-nullable onChanged --- .../frontend/lib/components/sdk_dropdown.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart index 15c8cbdea97d..bfa22578757c 100644 --- a/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart +++ b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart @@ -23,7 +23,7 @@ import 'builders/sdks.dart'; class SdkDropdown extends StatelessWidget { final String sdkId; - final ValueChanged onChanged; + final ValueChanged onChanged; const SdkDropdown({ required this.sdkId, required this.onChanged, @@ -40,7 +40,11 @@ class SdkDropdown extends StatelessWidget { return _DropdownWrapper( child: DropdownButton( value: sdkId, - onChanged: onChanged, + onChanged: (value) { + if (value != null) { + onChanged(value); + } + }, items: sdks .map( (sdk) => DropdownMenuItem( From a6597d434a3aed640fc230976afd3637217d8792 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 21 Nov 2022 21:44:55 +0600 Subject: [PATCH 24/65] untested refinement --- .../frontend/lib/cache/user_progress.dart | 28 +++----- .../tour-of-beam/frontend/lib/config.dart | 4 +- .../frontend/lib/constants/sizes.dart | 1 - .../pages/tour/controllers/content_tree.dart | 1 + .../lib/pages/tour/controllers/unit.dart | 18 +++-- .../frontend/lib/pages/tour/state.dart | 43 ++++++++---- ...cator.dart => completeness_indicator.dart} | 4 +- .../lib/pages/tour/widgets/content.dart | 30 +++------ .../lib/pages/tour/widgets/group_title.dart | 66 ++++++++----------- .../frontend/lib/pages/tour/widgets/unit.dart | 19 ++---- .../client/cloud_functions_client.dart | 5 +- 11 files changed, 96 insertions(+), 123 deletions(-) rename learning/tour-of-beam/frontend/lib/pages/tour/widgets/{unit_progress_indicator.dart => completeness_indicator.dart} (95%) diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart index e4541f316518..5761c5fc456d 100644 --- a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart @@ -20,44 +20,35 @@ import 'dart:async'; import 'package:get_it/get_it.dart'; -import '../auth/notifier.dart'; import '../models/user_progress.dart'; import '../state.dart'; import 'cache.dart'; class UserProgressCache extends Cache { - final _app = GetIt.instance.get(); - final _auth = GetIt.instance.get(); - UserProgressCache({required super.client}) { - _auth.addListener(_onChanged); - _app.addListener(_onChanged); - } + UserProgressCache({required super.client}); final _completedUnits = {}; Future?>? _future; - void _onChanged() { - if (_app.sdkId != null) { - updateCompletedUnits(_app.sdkId!); - } + bool isUnitCompleted(String? unitId) { + return getCompletedUnits().contains(unitId); } - Set updateCompletedUnits(String sdkId) { + void updateCompletedUnits() { _future = null; - return getCompletedUnits(sdkId); + getCompletedUnits(); } - Set getCompletedUnits(String sdkId) { - print(['gcu', _future]); - if (_future == null) { + Set getCompletedUnits() { + final sdkId = GetIt.instance.get().sdkId; + if (sdkId != null && _future == null) { unawaited(_loadCompletedUnits(sdkId)); } return _completedUnits; } - Future> _loadCompletedUnits(String sdkId) async { - print(['lcu']); + Future _loadCompletedUnits(String sdkId) async { _future = client.getUserProgress(sdkId); final result = await _future; @@ -70,6 +61,5 @@ class UserProgressCache extends Cache { } } notifyListeners(); - return _completedUnits; } } diff --git a/learning/tour-of-beam/frontend/lib/config.dart b/learning/tour-of-beam/frontend/lib/config.dart index 7c64c3986b81..b7ed542e1b05 100644 --- a/learning/tour-of-beam/frontend/lib/config.dart +++ b/learning/tour-of-beam/frontend/lib/config.dart @@ -18,8 +18,8 @@ // TODO(alexeyinkin): Generate this file on deployment. -const _cloudFunctionsProjectRegion = 'us-east1'; -const _cloudFunctionsProjectId = 'sandbox-playground-002'; +const _cloudFunctionsProjectRegion = 'us-central1'; +const _cloudFunctionsProjectId = 'tour-of-beam-2'; const cloudFunctionsBaseUrl = 'https://' '$_cloudFunctionsProjectRegion-$_cloudFunctionsProjectId' '.cloudfunctions.net'; diff --git a/learning/tour-of-beam/frontend/lib/constants/sizes.dart b/learning/tour-of-beam/frontend/lib/constants/sizes.dart index bb9a665c8a30..53ad1c7c2d03 100644 --- a/learning/tour-of-beam/frontend/lib/constants/sizes.dart +++ b/learning/tour-of-beam/frontend/lib/constants/sizes.dart @@ -22,7 +22,6 @@ class TobSizes { } class ScreenSizes { - // TODO(nausharipov): name better static const medium = 1024; } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart index 5cf1778171e5..bcdb686a10b7 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart @@ -28,6 +28,7 @@ import '../../../models/unit.dart'; class ContentTreeController extends ChangeNotifier { String _sdkId; List _treeIds; + // TODO(nausharipov): non-nullable currentNode? NodeModel? _currentNode; final _contentTreeCache = GetIt.instance.get(); final _expandedIds = {}; diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart index 9c1696b6b2bb..45bde4993d20 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart @@ -19,22 +19,20 @@ import 'package:flutter/widgets.dart'; import 'package:get_it/get_it.dart'; -import '../../../cache/user_progress.dart'; import '../../../repositories/client/client.dart'; class UnitController extends ChangeNotifier { - // TODO(nausharipov): finish - // final String unitId; - // final String sdkId; + final String unitId; + final String sdkId; - // UnitController({ - // required this.unitId, - // required this.sdkId, - // }); + UnitController({ + required this.unitId, + required this.sdkId, + }); - Future completeUnit(String sdkId, String unitId) async { + Future completeUnit() async { final client = GetIt.instance.get(); await client.postUnitComplete(sdkId, unitId); - GetIt.instance.get().updateCompletedUnits(sdkId); + notifyListeners(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index ddac48da04b2..536864721268 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -21,7 +21,9 @@ import 'package:flutter/widgets.dart'; import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; +import '../../auth/notifier.dart'; import '../../cache/unit_content.dart'; +import '../../cache/user_progress.dart'; import '../../config.dart'; import '../../models/unit.dart'; import '../../models/unit_content.dart'; @@ -33,9 +35,11 @@ import 'path.dart'; class TourNotifier extends ChangeNotifier with PageStateMixin { final ContentTreeController contentTreeController; final PlaygroundController playgroundController; - final UnitController unitController; + late UnitController currentUnitController; final _appNotifier = GetIt.instance.get(); + final _authNotifier = GetIt.instance.get(); final _unitContentCache = GetIt.instance.get(); + final _userProgressCache = GetIt.instance.get(); UnitContentModel? _currentUnitContent; TourNotifier({ @@ -45,24 +49,27 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { initialSdkId: initialSdkId, initialTreeIds: initialTreeIds, ), - unitController = UnitController( - // TODO(nausharipov): finish - // unitId: contentTreeController.currentNode.id, - // sdkId: initialSdkId, - ), playgroundController = _createPlaygroundController(initialSdkId) { - contentTreeController.addListener(_onChanged); - _unitContentCache.addListener(_onChanged); + contentTreeController.addListener(_onUnitChanged); + _unitContentCache.addListener(_onUnitChanged); _appNotifier.addListener(_onAppNotifierChanged); - _onChanged(); + _appNotifier.addListener(_onUserProgressChanged); + _authNotifier.addListener(_onUserProgressChanged); + _onUnitChanged(); } + // TODO(nausharipov): currentUnitId getter? + @override PagePath get path => TourPath( sdkId: contentTreeController.sdkId, treeIds: contentTreeController.treeIds, ); + void _onUserProgressChanged() { + _userProgressCache.updateCompletedUnits(); + } + void _onAppNotifierChanged() { final sdkId = _appNotifier.sdkId; if (sdkId != null) { @@ -71,7 +78,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { } } - void _onChanged() { + void _onUnitChanged() { emitPathChanged(); final currentNode = contentTreeController.currentNode; if (currentNode is UnitModel) { @@ -79,7 +86,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { contentTreeController.sdkId, currentNode.id, ); - + _setCurrentUnitController(contentTreeController.sdkId, currentNode.id); _setCurrentUnitContent(content); } else { _emptyPlayground(); @@ -90,6 +97,13 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { UnitContentModel? get currentUnitContent => _currentUnitContent; + void _setCurrentUnitController(String sdkId, String unitId) { + currentUnitController = UnitController( + unitId: unitId, + sdkId: sdkId, + )..addListener(_onUserProgressChanged); + } + void _setCurrentUnitContent(UnitContentModel? content) { if (content == _currentUnitContent) { return; @@ -168,8 +182,11 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { @override void dispose() { - _unitContentCache.removeListener(_onChanged); - contentTreeController.removeListener(_onChanged); + _unitContentCache.removeListener(_onUnitChanged); + contentTreeController.removeListener(_onUnitChanged); + _appNotifier.removeListener(_onUserProgressChanged); + _authNotifier.removeListener(_onUserProgressChanged); + currentUnitController.removeListener(_onUserProgressChanged); _appNotifier.removeListener(_onAppNotifierChanged); super.dispose(); } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit_progress_indicator.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/completeness_indicator.dart similarity index 95% rename from learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit_progress_indicator.dart rename to learning/tour-of-beam/frontend/lib/pages/tour/widgets/completeness_indicator.dart index 5671cd70beb1..4714e0dcbc2e 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit_progress_indicator.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/completeness_indicator.dart @@ -22,11 +22,11 @@ import 'package:playground_components/playground_components.dart'; import '../../../generated/assets.gen.dart'; -class UnitProgressIndicator extends StatelessWidget { +class CompletenessIndicator extends StatelessWidget { final bool isCompleted; final bool isSelected; - const UnitProgressIndicator({ + const CompletenessIndicator({ required this.isCompleted, required this.isSelected, }); diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart index 80f7860bfbd2..8940a42716e0 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart @@ -17,14 +17,13 @@ */ import 'package:easy_localization/easy_localization.dart'; -import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; +import '../../../auth/notifier.dart'; import '../../../cache/user_progress.dart'; import '../../../constants/sizes.dart'; -import '../../../state.dart'; import '../state.dart'; import 'unit_content.dart'; @@ -104,17 +103,15 @@ class _CompleteUnitButton extends StatelessWidget { @override Widget build(BuildContext context) { final themeData = Theme.of(context); - final cache = GetIt.instance.get(); - final app = GetIt.instance.get(); + final userProgress = GetIt.instance.get(); + final auth = GetIt.instance.get(); return AnimatedBuilder( - animation: cache, + animation: userProgress, builder: (context, child) { - // TODO(nausharipov): finish - final isDisabled = cache.getCompletedUnits(app.sdkId!).contains( - notifier.contentTreeController.currentNode?.id, - ) || - FirebaseAuth.instance.currentUser == null; + final isCompleted = userProgress + .isUnitCompleted(notifier.contentTreeController.currentNode?.id); + final isDisabled = !auth.isAuthenticated || isCompleted; return Flexible( child: OutlinedButton( @@ -131,7 +128,8 @@ class _CompleteUnitButton extends StatelessWidget { ), ), ), - onPressed: isDisabled ? null : _completeUnit, + onPressed: + isDisabled ? null : notifier.currentUnitController.completeUnit, child: const Text( 'pages.tour.completeUnit', overflow: TextOverflow.ellipsis, @@ -141,14 +139,4 @@ class _CompleteUnitButton extends StatelessWidget { }, ); } - - void _completeUnit() { - // TODO(nausharipov): finish - final app = GetIt.instance.get(); - - notifier.unitController.completeUnit( - app.sdkId!, - notifier.contentTreeController.currentNode!.id, - ); - } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart index 5fb1833555cf..271e775ea46a 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart @@ -23,8 +23,7 @@ import 'package:playground_components/playground_components.dart'; import '../../../cache/user_progress.dart'; import '../../../models/group.dart'; import '../../../models/node.dart'; -import '../../../state.dart'; -import 'unit_progress_indicator.dart'; +import 'completeness_indicator.dart'; class GroupTitleWidget extends StatelessWidget { final GroupModel group; @@ -52,52 +51,43 @@ class GroupTitleWidget extends StatelessWidget { } } -// TODO(nausharipov): finish class _GroupProgressIndicator extends StatelessWidget { final GroupModel group; const _GroupProgressIndicator({required this.group}); @override Widget build(BuildContext context) { - final cache = GetIt.instance.get(); - final app = GetIt.instance.get(); + final userProgress = GetIt.instance.get(); return AnimatedBuilder( - animation: app, - builder: (context, child) => AnimatedBuilder( - animation: cache, - builder: (context, child) { - final progress = _getGroupProgress( - group.nodes, - // TODO(nausharipov): get once somewhere - cache.getCompletedUnits(app.sdkId!), - ); - - if (progress == 1) { - // TODO(nausharipov): finish - return const UnitProgressIndicator( - isCompleted: true, - isSelected: false, - ); - } + animation: userProgress, + builder: (context, child) { + final progress = _getGroupProgress( + group.nodes, + userProgress.getCompletedUnits(), + ); - return Container( - margin: const EdgeInsets.symmetric( - horizontal: BeamSizes.size6, - ), - height: BeamSizes.size8, - width: BeamSizes.size8, - child: CircularProgressIndicator( - strokeWidth: BeamSizes.size3, - color: BeamColors.green, - backgroundColor: Theme.of(context) - .extension()! - .unselectedProgressColor, - value: progress, - ), + if (progress == 1) { + return const CompletenessIndicator( + isCompleted: true, + isSelected: false, ); - }, - ), + } + + return Container( + margin: const EdgeInsets.symmetric(horizontal: BeamSizes.size6), + height: BeamSizes.size8, + width: BeamSizes.size8, + child: CircularProgressIndicator( + strokeWidth: BeamSizes.size3, + color: BeamColors.green, + backgroundColor: Theme.of(context) + .extension()! + .unselectedProgressColor, + value: progress, + ), + ); + }, ); } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart index 085012406eec..0d537676a8b9 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart @@ -22,9 +22,8 @@ import 'package:playground_components/playground_components.dart'; import '../../../cache/user_progress.dart'; import '../../../models/unit.dart'; -import '../../../state.dart'; import '../controllers/content_tree.dart'; -import 'unit_progress_indicator.dart'; +import 'completeness_indicator.dart'; class UnitWidget extends StatelessWidget { final UnitModel unit; @@ -37,8 +36,7 @@ class UnitWidget extends StatelessWidget { @override Widget build(BuildContext context) { - final cache = GetIt.instance.get(); - final app = GetIt.instance.get(); + final userProgress = GetIt.instance.get(); return AnimatedBuilder( animation: contentTreeController, @@ -55,16 +53,11 @@ class UnitWidget extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: BeamSizes.size10), child: Row( children: [ - // TODO(nausharipov): finish AnimatedBuilder( - animation: app, - builder: (context, child) => AnimatedBuilder( - animation: cache, - builder: (context, child) => UnitProgressIndicator( - isCompleted: - cache.getCompletedUnits(app.sdkId!).contains(unit.id), - isSelected: isSelected, - ), + animation: userProgress, + builder: (context, child) => CompletenessIndicator( + isCompleted: userProgress.isUnitCompleted(unit.id), + isSelected: isSelected, ), ), Expanded( diff --git a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart index 02472ada6cb7..c9b53295b2d2 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart @@ -32,7 +32,7 @@ import '../models/get_sdks_response.dart'; import '../models/get_user_progress_response.dart'; import 'client.dart'; -// TODO(nausharipov): add an abstraction layer for calling API methods +// TODO(nausharipov): add abstraction layers for calling API methods class CloudFunctionsTobClient extends TobClient { @override Future getSdks() async { @@ -48,7 +48,6 @@ class CloudFunctionsTobClient extends TobClient { @override Future getContentTree(String sdkId) async { - // TODO(nausharipov): finish final json = await http.get( Uri.parse( '$cloudFunctionsBaseUrl/getContentTree?sdk=$sdkId', @@ -74,7 +73,6 @@ class CloudFunctionsTobClient extends TobClient { @override Future?> getUserProgress(String sdkId) async { - // TODO(nausharipov): check auth final token = await GetIt.instance.get().token; if (token == null) { return null; @@ -87,7 +85,6 @@ class CloudFunctionsTobClient extends TobClient { HttpHeaders.authorizationHeader: 'Bearer $token', }, ); - print(['gup', json]); final map = jsonDecode(utf8.decode(json.bodyBytes)) as Map; final response = GetUserProgressResponse.fromJson(map); return response.units; From 2068ce9e8da8b6caa41e1be09dfa04e26e2ca567 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 21 Nov 2022 21:50:25 +0600 Subject: [PATCH 25/65] deleted show sdk selector --- .../frontend/lib/components/scaffold.dart | 17 +++++++---------- .../frontend/lib/pages/tour/screen.dart | 1 - .../frontend/lib/pages/welcome/screen.dart | 1 - 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/components/scaffold.dart b/learning/tour-of-beam/frontend/lib/components/scaffold.dart index 3bb6f5948360..08718198bdd2 100644 --- a/learning/tour-of-beam/frontend/lib/components/scaffold.dart +++ b/learning/tour-of-beam/frontend/lib/components/scaffold.dart @@ -30,12 +30,10 @@ import 'sdk_dropdown.dart'; class TobScaffold extends StatelessWidget { final Widget child; - final bool showSdkSelector; const TobScaffold({ super.key, required this.child, - required this.showSdkSelector, }); @override @@ -44,14 +42,13 @@ class TobScaffold extends StatelessWidget { appBar: AppBar( automaticallyImplyLeading: false, title: const Logo(), - actions: [ - if (showSdkSelector) - const _ActionVerticalPadding(child: _SdkSelector()), - const SizedBox(width: BeamSizes.size12), - const _ActionVerticalPadding(child: ToggleThemeButton()), - const SizedBox(width: BeamSizes.size6), - const _Profile(), - const SizedBox(width: BeamSizes.size16), + actions: const [ + _ActionVerticalPadding(child: _SdkSelector()), + SizedBox(width: BeamSizes.size12), + _ActionVerticalPadding(child: ToggleThemeButton()), + SizedBox(width: BeamSizes.size6), + _Profile(), + SizedBox(width: BeamSizes.size16), ], ), body: Column( diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart index 6ba9ba2e1185..3557111c0f76 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart @@ -34,7 +34,6 @@ class TourScreen extends StatelessWidget { @override Widget build(BuildContext context) { return TobScaffold( - showSdkSelector: true, child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns ? _WideTour(notifier) : _NarrowTour(notifier), diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart index 80f4e1ebe989..b37724f77ba2 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart @@ -44,7 +44,6 @@ class WelcomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return TobScaffold( - showSdkSelector: true, child: SingleChildScrollView( child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns ? _WideWelcome(notifier) From 52838e500fc106414dbb47d0c05fe4042c812509 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 21 Nov 2022 21:54:53 +0600 Subject: [PATCH 26/65] notifier objects naming --- .../lib/components/builders/content_tree.dart | 6 ++-- .../lib/components/builders/sdks.dart | 6 ++-- .../frontend/lib/components/scaffold.dart | 10 +++---- .../pages/tour/controllers/content_tree.dart | 8 ++--- .../frontend/lib/pages/tour/state.dart | 30 +++++++++---------- .../frontend/lib/pages/welcome/screen.dart | 16 +++++----- 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart b/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart index 1ee9a3b87d01..d16bc23f9896 100644 --- a/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart @@ -33,13 +33,13 @@ class ContentTreeBuilder extends StatelessWidget { @override Widget build(BuildContext context) { - final cache = GetIt.instance.get(); + final contentTree = GetIt.instance.get(); return AnimatedBuilder( - animation: cache, + animation: contentTree, builder: (context, child) => builder( context, - cache.getContentTree(sdkId), + contentTree.getContentTree(sdkId), child, ), ); diff --git a/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart b/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart index 8aeea1461300..901e1be798d9 100644 --- a/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart +++ b/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart @@ -31,11 +31,11 @@ class SdksBuilder extends StatelessWidget { @override Widget build(BuildContext context) { - final cache = GetIt.instance.get(); + final sdk = GetIt.instance.get(); return AnimatedBuilder( - animation: cache, - builder: (context, child) => builder(context, cache.getSdks(), child), + animation: sdk, + builder: (context, child) => builder(context, sdk.getSdks(), child), ); } } diff --git a/learning/tour-of-beam/frontend/lib/components/scaffold.dart b/learning/tour-of-beam/frontend/lib/components/scaffold.dart index 08718198bdd2..c1300a064c26 100644 --- a/learning/tour-of-beam/frontend/lib/components/scaffold.dart +++ b/learning/tour-of-beam/frontend/lib/components/scaffold.dart @@ -95,15 +95,15 @@ class _SdkSelector extends StatelessWidget { @override Widget build(BuildContext context) { - final notifier = GetIt.instance.get(); + final app = GetIt.instance.get(); return AnimatedBuilder( - animation: notifier, - builder: (context, child) => notifier.sdkId == null + animation: app, + builder: (context, child) => app.sdkId == null ? Container() : SdkDropdown( - sdkId: notifier.sdkId!, + sdkId: app.sdkId!, onChanged: (sdkId) { - notifier.sdkId = sdkId; + app.sdkId = sdkId; }, ), ); diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart index bcdb686a10b7..a1a28ef5eec7 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart @@ -30,7 +30,7 @@ class ContentTreeController extends ChangeNotifier { List _treeIds; // TODO(nausharipov): non-nullable currentNode? NodeModel? _currentNode; - final _contentTreeCache = GetIt.instance.get(); + final _contentTree = GetIt.instance.get(); final _expandedIds = {}; Set get expandedIds => _expandedIds; @@ -42,7 +42,7 @@ class ContentTreeController extends ChangeNotifier { _treeIds = initialTreeIds { _expandedIds.addAll(initialTreeIds); - _contentTreeCache.addListener(_onContentTreeCacheChange); + _contentTree.addListener(_onContentTreeCacheChange); _onContentTreeCacheChange(); } @@ -98,7 +98,7 @@ class ContentTreeController extends ChangeNotifier { } void _onContentTreeCacheChange() { - final contentTree = _contentTreeCache.getContentTree(_sdkId); + final contentTree = _contentTree.getContentTree(_sdkId); if (contentTree == null) { return; } @@ -112,7 +112,7 @@ class ContentTreeController extends ChangeNotifier { @override void dispose() { - _contentTreeCache.removeListener(_onContentTreeCacheChange); + _contentTree.removeListener(_onContentTreeCacheChange); super.dispose(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 536864721268..1d7a65d19e42 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -36,10 +36,10 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { final ContentTreeController contentTreeController; final PlaygroundController playgroundController; late UnitController currentUnitController; - final _appNotifier = GetIt.instance.get(); - final _authNotifier = GetIt.instance.get(); - final _unitContentCache = GetIt.instance.get(); - final _userProgressCache = GetIt.instance.get(); + final _app = GetIt.instance.get(); + final _auth = GetIt.instance.get(); + final _unitContent = GetIt.instance.get(); + final _userProgress = GetIt.instance.get(); UnitContentModel? _currentUnitContent; TourNotifier({ @@ -51,10 +51,10 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { ), playgroundController = _createPlaygroundController(initialSdkId) { contentTreeController.addListener(_onUnitChanged); - _unitContentCache.addListener(_onUnitChanged); - _appNotifier.addListener(_onAppNotifierChanged); - _appNotifier.addListener(_onUserProgressChanged); - _authNotifier.addListener(_onUserProgressChanged); + _unitContent.addListener(_onUnitChanged); + _app.addListener(_onAppNotifierChanged); + _app.addListener(_onUserProgressChanged); + _auth.addListener(_onUserProgressChanged); _onUnitChanged(); } @@ -67,11 +67,11 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { ); void _onUserProgressChanged() { - _userProgressCache.updateCompletedUnits(); + _userProgress.updateCompletedUnits(); } void _onAppNotifierChanged() { - final sdkId = _appNotifier.sdkId; + final sdkId = _app.sdkId; if (sdkId != null) { playgroundController.setSdk(Sdk.parseOrCreate(sdkId)); contentTreeController.sdkId = sdkId; @@ -82,7 +82,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { emitPathChanged(); final currentNode = contentTreeController.currentNode; if (currentNode is UnitModel) { - final content = _unitContentCache.getUnitContent( + final content = _unitContent.getUnitContent( contentTreeController.sdkId, currentNode.id, ); @@ -182,12 +182,12 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { @override void dispose() { - _unitContentCache.removeListener(_onUnitChanged); + _unitContent.removeListener(_onUnitChanged); contentTreeController.removeListener(_onUnitChanged); - _appNotifier.removeListener(_onUserProgressChanged); - _authNotifier.removeListener(_onUserProgressChanged); + _app.removeListener(_onUserProgressChanged); + _auth.removeListener(_onUserProgressChanged); currentUnitController.removeListener(_onUserProgressChanged); - _appNotifier.removeListener(_onAppNotifierChanged); + _app.removeListener(_onAppNotifierChanged); super.dispose(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart index b37724f77ba2..79745bddf90a 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart @@ -99,7 +99,7 @@ class _SdkSelection extends StatelessWidget { @override Widget build(BuildContext context) { - final appNotifier = GetIt.instance.get(); + final app = GetIt.instance.get(); return Container( constraints: BoxConstraints( minHeight: MediaQuery.of(context).size.height - @@ -132,13 +132,13 @@ class _SdkSelection extends StatelessWidget { } return AnimatedBuilder( - animation: appNotifier, + animation: app, builder: (context, child) => _Buttons( sdks: sdks, - sdkId: appNotifier.sdkId, - setSdkId: (v) => appNotifier.sdkId = v, + sdkId: app.sdkId, + setSdkId: (v) => app.sdkId = v, onStartPressed: () { - _startTour(appNotifier.sdkId); + _startTour(app.sdkId); }, ), ); @@ -165,11 +165,11 @@ class _TourSummary extends StatelessWidget { @override Widget build(BuildContext context) { - final appNotifier = GetIt.instance.get(); + final app = GetIt.instance.get(); return AnimatedBuilder( - animation: appNotifier, + animation: app, builder: (context, child) { - final sdkId = appNotifier.sdkId; + final sdkId = app.sdkId; if (sdkId == null) { return Container(); } From 3df27bc7fc71f12d48b3aa0bf5d58e57ba1327b9 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 22 Nov 2022 15:12:05 +0600 Subject: [PATCH 27/65] untested refinement (1) --- .../frontend/lib/cache/user_progress.dart | 1 + .../frontend/lib/components/functions.dart | 31 +++++++++++++++++++ .../frontend/lib/components/login/button.dart | 25 ++------------- .../lib/components/login/content.dart | 3 ++ .../lib/components/profile/avatar.dart | 26 ++-------------- .../lib/components/profile/user_menu.dart | 1 + .../frontend/lib/components/scaffold.dart | 12 +++---- .../frontend/lib/components/sdk_dropdown.dart | 7 +++-- .../frontend/lib/pages/tour/state.dart | 28 ++++++++++------- .../lib/pages/tour/widgets/content.dart | 12 +++---- .../frontend/lib/pages/welcome/screen.dart | 6 ++-- 11 files changed, 75 insertions(+), 77 deletions(-) create mode 100644 learning/tour-of-beam/frontend/lib/components/functions.dart diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart index 5761c5fc456d..dbbe2e381d52 100644 --- a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart @@ -60,6 +60,7 @@ class UserProgressCache extends Cache { } } } + notifyListeners(); } } diff --git a/learning/tour-of-beam/frontend/lib/components/functions.dart b/learning/tour-of-beam/frontend/lib/components/functions.dart new file mode 100644 index 000000000000..562aa34b29d2 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/components/functions.dart @@ -0,0 +1,31 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:playground_components/playground_components.dart'; + +import 'login/content.dart'; +import 'profile/user_menu.dart'; + +void openLoginOverlay(BuildContext context, [User? user]) { + final overlayCloser = PublicNotifier(); + final overlay = OverlayEntry( + builder: (context) { + return DismissibleOverlay( + close: overlayCloser.notifyPublic, + child: Positioned( + right: BeamSizes.size10, + top: BeamSizes.appBarHeight, + child: user == null + ? LoginContent( + onLoggedIn: overlayCloser.notifyPublic, + ) + : UserMenu( + onLoggedOut: overlayCloser.notifyPublic, + user: user, + ), + ), + ); + }, + ); + overlayCloser.addListener(overlay.remove); + Overlay.of(context)?.insert(overlay); +} diff --git a/learning/tour-of-beam/frontend/lib/components/login/button.dart b/learning/tour-of-beam/frontend/lib/components/login/button.dart index 197699b55402..1ba2ad19dc0f 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/button.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/button.dart @@ -18,9 +18,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:playground_components/playground_components.dart'; -import 'content.dart'; +import '../functions.dart'; class LoginButton extends StatelessWidget { const LoginButton(); @@ -29,29 +28,9 @@ class LoginButton extends StatelessWidget { Widget build(BuildContext context) { return TextButton( onPressed: () { - _openOverlay(context); + openLoginOverlay(context); }, child: const Text('ui.signIn').tr(), ); } - - void _openOverlay(BuildContext context) { - final overlayCloser = PublicNotifier(); - final overlay = OverlayEntry( - builder: (context) { - return DismissibleOverlay( - close: overlayCloser.notifyPublic, - child: Positioned( - right: BeamSizes.size10, - top: BeamSizes.appBarHeight, - child: LoginContent( - onLoggedIn: overlayCloser.notifyPublic, - ), - ), - ); - }, - ); - overlayCloser.addListener(overlay.remove); - Overlay.of(context)?.insert(overlay); - } } diff --git a/learning/tour-of-beam/frontend/lib/components/login/content.dart b/learning/tour-of-beam/frontend/lib/components/login/content.dart index 7a73ef1d92ba..4b097452b578 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/content.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/content.dart @@ -29,6 +29,7 @@ import '../../generated/assets.gen.dart'; class LoginContent extends StatelessWidget { final VoidCallback onLoggedIn; + const LoginContent({ required this.onLoggedIn, }); @@ -60,6 +61,7 @@ class LoginContent extends StatelessWidget { class _Body extends StatelessWidget { final Widget child; + const _Body({required this.child}); @override @@ -92,6 +94,7 @@ class _Divider extends StatelessWidget { class _BrandedLoginButtons extends StatelessWidget { final VoidCallback onLoggedIn; + const _BrandedLoginButtons({ required this.onLoggedIn, }); diff --git a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart index 498b5e2d70af..19fe698f3731 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart @@ -21,7 +21,7 @@ import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; import '../../generated/assets.gen.dart'; -import 'user_menu.dart'; +import '../functions.dart'; class Avatar extends StatelessWidget { final User user; @@ -32,7 +32,7 @@ class Avatar extends StatelessWidget { final photoUrl = user.photoURL; return GestureDetector( onTap: () { - _openOverlay(context); + openLoginOverlay(context, user); }, child: CircleAvatar( backgroundColor: BeamColors.white, @@ -43,26 +43,4 @@ class Avatar extends StatelessWidget { ), ); } - - void _openOverlay(BuildContext context) { - final overlayCloser = PublicNotifier(); - OverlayEntry? overlay; - overlay = OverlayEntry( - builder: (context) { - overlayCloser.addListener(overlay!.remove); - return DismissibleOverlay( - close: overlayCloser.notifyPublic, - child: Positioned( - right: BeamSizes.size10, - top: BeamSizes.appBarHeight, - child: UserMenu( - onLoggedOut: overlayCloser.notifyPublic, - user: user, - ), - ), - ); - }, - ); - Overlay.of(context)?.insert(overlay); - } } diff --git a/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart index cbd97a74f6d4..841c1b8277de 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart @@ -106,6 +106,7 @@ class _Info extends StatelessWidget { class _Buttons extends StatelessWidget { final VoidCallback closeOverlay; + const _Buttons({ required this.closeOverlay, }); diff --git a/learning/tour-of-beam/frontend/lib/components/scaffold.dart b/learning/tour-of-beam/frontend/lib/components/scaffold.dart index c1300a064c26..49bd2f660639 100644 --- a/learning/tour-of-beam/frontend/lib/components/scaffold.dart +++ b/learning/tour-of-beam/frontend/lib/components/scaffold.dart @@ -47,7 +47,7 @@ class TobScaffold extends StatelessWidget { SizedBox(width: BeamSizes.size12), _ActionVerticalPadding(child: ToggleThemeButton()), SizedBox(width: BeamSizes.size6), - _Profile(), + _ActionVerticalPadding(child: _Profile()), SizedBox(width: BeamSizes.size16), ], ), @@ -66,12 +66,10 @@ class _Profile extends StatelessWidget { @override Widget build(BuildContext context) { - return _ActionVerticalPadding( - child: StreamBuilder( - stream: FirebaseAuth.instance.userChanges(), - builder: (context, user) => - user.hasData ? Avatar(user: user.data!) : const LoginButton(), - ), + return StreamBuilder( + stream: FirebaseAuth.instance.userChanges(), + builder: (context, user) => + user.hasData ? Avatar(user: user.data!) : const LoginButton(), ); } } diff --git a/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart index bfa22578757c..9e84e3698e37 100644 --- a/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart +++ b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart @@ -24,6 +24,7 @@ import 'builders/sdks.dart'; class SdkDropdown extends StatelessWidget { final String sdkId; final ValueChanged onChanged; + const SdkDropdown({ required this.sdkId, required this.onChanged, @@ -40,9 +41,9 @@ class SdkDropdown extends StatelessWidget { return _DropdownWrapper( child: DropdownButton( value: sdkId, - onChanged: (value) { - if (value != null) { - onChanged(value); + onChanged: (sdk) { + if (sdk != null) { + onChanged(sdk); } }, items: sdks diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 1d7a65d19e42..708856b769d7 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -66,6 +66,21 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { treeIds: contentTreeController.treeIds, ); + bool isCurrentUnitCompleted() { + return _userProgress.isUnitCompleted( + contentTreeController.currentNode?.id, + ); + } + + UnitContentModel? get currentUnitContent => _currentUnitContent; + + void _setCurrentUnitController(String sdkId, String unitId) { + currentUnitController = UnitController( + unitId: unitId, + sdkId: sdkId, + )..addListener(_onUserProgressChanged); + } + void _onUserProgressChanged() { _userProgress.updateCompletedUnits(); } @@ -95,15 +110,6 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { notifyListeners(); } - UnitContentModel? get currentUnitContent => _currentUnitContent; - - void _setCurrentUnitController(String sdkId, String unitId) { - currentUnitController = UnitController( - unitId: unitId, - sdkId: sdkId, - )..addListener(_onUserProgressChanged); - } - void _setCurrentUnitContent(UnitContentModel? content) { if (content == _currentUnitContent) { return; @@ -184,10 +190,10 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { void dispose() { _unitContent.removeListener(_onUnitChanged); contentTreeController.removeListener(_onUnitChanged); - _app.removeListener(_onUserProgressChanged); - _auth.removeListener(_onUserProgressChanged); currentUnitController.removeListener(_onUserProgressChanged); + _app.removeListener(_onUserProgressChanged); _app.removeListener(_onAppNotifierChanged); + _auth.removeListener(_onUserProgressChanged); super.dispose(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart index 8940a42716e0..a67c033722f3 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart @@ -97,8 +97,9 @@ class _ContentFooter extends StatelessWidget { } class _CompleteUnitButton extends StatelessWidget { - final TourNotifier notifier; - const _CompleteUnitButton(this.notifier); + // TODO(nausharipov): rename notifier to tour everywhere? + final TourNotifier tour; + const _CompleteUnitButton(this.tour); @override Widget build(BuildContext context) { @@ -109,9 +110,8 @@ class _CompleteUnitButton extends StatelessWidget { return AnimatedBuilder( animation: userProgress, builder: (context, child) { - final isCompleted = userProgress - .isUnitCompleted(notifier.contentTreeController.currentNode?.id); - final isDisabled = !auth.isAuthenticated || isCompleted; + final isDisabled = + !auth.isAuthenticated || tour.isCurrentUnitCompleted(); return Flexible( child: OutlinedButton( @@ -129,7 +129,7 @@ class _CompleteUnitButton extends StatelessWidget { ), ), onPressed: - isDisabled ? null : notifier.currentUnitController.completeUnit, + isDisabled ? null : tour.currentUnitController.completeUnit, child: const Text( 'pages.tour.completeUnit', overflow: TextOverflow.ellipsis, diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart index 79745bddf90a..ebb594ea9044 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart @@ -133,7 +133,7 @@ class _SdkSelection extends StatelessWidget { return AnimatedBuilder( animation: app, - builder: (context, child) => _Buttons( + builder: (context, child) => _SdkButtons( sdks: sdks, sdkId: app.sdkId, setSdkId: (v) => app.sdkId = v, @@ -282,13 +282,13 @@ class _IntroTextBody extends StatelessWidget { } } -class _Buttons extends StatelessWidget { +class _SdkButtons extends StatelessWidget { final List sdks; final String? sdkId; final ValueChanged setSdkId; final VoidCallback onStartPressed; - const _Buttons({ + const _SdkButtons({ required this.sdks, required this.sdkId, required this.setSdkId, From 0b6fc8f805d3417f819ebafadc40f2571d73df99 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 22 Nov 2022 21:07:35 +0600 Subject: [PATCH 28/65] candidate repository --- .../frontend/lib/repositories/exception.dart | 33 +++++ .../frontend/lib/repositories/repository.dart | 121 ++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 learning/tour-of-beam/frontend/lib/repositories/exception.dart create mode 100644 learning/tour-of-beam/frontend/lib/repositories/repository.dart diff --git a/learning/tour-of-beam/frontend/lib/repositories/exception.dart b/learning/tour-of-beam/frontend/lib/repositories/exception.dart new file mode 100644 index 000000000000..90595afcfc49 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/repositories/exception.dart @@ -0,0 +1,33 @@ +abstract class APIException implements Exception { + final String message; + const APIException(this.message); + + @override + String toString() => message; +} + +class APIGenericException extends APIException { + static const String type = 'API Call Failed'; + + const APIGenericException(String message) : super('$type: $message'); +} + +class APIAuthenticationException extends APIException { + static const String type = 'Authentication Failed'; + + const APIAuthenticationException(String message) : super('$type: $message'); +} + +class APIInternalServerException extends APIException { + static const String type = 'Internal Server Error'; + + const APIInternalServerException() + : super('$type: Something is wrong on backend side'); +} + +class InternalFrontendException extends APIException { + static const String type = 'Internal Error'; + + const InternalFrontendException() + : super('$type: Something is wrong on frontend side'); +} diff --git a/learning/tour-of-beam/frontend/lib/repositories/repository.dart b/learning/tour-of-beam/frontend/lib/repositories/repository.dart new file mode 100644 index 000000000000..618974c7ba1b --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/repositories/repository.dart @@ -0,0 +1,121 @@ +import 'dart:convert' as convert; + +import 'package:flutter/foundation.dart' show mustCallSuper; +import 'package:http/http.dart' as http; + +import '../config.dart'; +import 'exception.dart'; + +class APIRepository { + static const String _authority = cloudFunctionsBaseUrl; + + final String _basePath; + final Map _defaultHeaders; + + APIRepository({ + required String basePath, + Map defaultHeaders = const {}, + }) : _basePath = basePath, + _defaultHeaders = Map.unmodifiable(defaultHeaders); + + // A bit of wrapping for specifying mock client in tests. + http.Client _createClient() => http.Client(); + + Future _withClient(Future Function(http.Client) fn) async { + final client = _createClient(); + try { + return await fn(client); + } finally { + client.close(); + } + } + + /// Getting headers might be asynchronous, because a token + /// might need to be refreshed. + @mustCallSuper + Future> get headers async { + final headers = {'Content-Type': 'application/json; charset=utf-8'}; + return headers..addAll(_defaultHeaders); + } + + /// Sends a low-level get request. + Future get( + String path, { + Map? queryParams, + Map extraHeaders = const {}, + }) async { + final uri = Uri.https(_authority, _basePath + path, queryParams); + + final response = await _withClient( + (client) async => client.get( + uri, + headers: (await headers)..addAll(extraHeaders), + ), + ); + return _decode(response); + } + + /// Sends a low-level post request. + Future post( + String path, + Map data, { + Map? queryParams, + Map extraHeaders = const {}, + }) async { + final uri = Uri.https(_authority, _basePath + path, queryParams); + + final response = await _withClient( + (client) async => client.post( + uri, + headers: (await headers)..addAll(extraHeaders), + body: convert.jsonEncode(data), + ), + ); + return _decode(response); + } + + void _handleError(http.Response response) { + if (response.statusCode == 500) { + throw const APIInternalServerException(); + } + + final utf8Body = convert.utf8.decode(response.bodyBytes); + try { + final jsonResponse = convert.jsonDecode(utf8Body); + if (response.statusCode == 401) { + throw APIAuthenticationException(jsonResponse['message'] ?? utf8Body); + } + throw APIGenericException(jsonResponse['message'] ?? utf8Body); + } on FormatException { + throw APIGenericException(utf8Body); + } + } + + dynamic _decode(http.Response response) { + if (response.statusCode >= 200 && response.statusCode < 400) { + final utf8Body = convert.utf8.decode(response.bodyBytes); + if (utf8Body.isEmpty) { + return null; + } + try { + return convert.jsonDecode(utf8Body); + } on FormatException { + throw APIGenericException(utf8Body); + } + } + _handleError(response); + } +} + +class TestAPIRepository extends APIRepository { + final http.Client client; + + TestAPIRepository( + this.client, { + required super.basePath, + super.defaultHeaders, + }); + + @override + http.Client _createClient() => client; +} From 7fbaf3843394530602a87805fa274ace7620ae29 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Wed, 23 Nov 2022 15:21:56 +0600 Subject: [PATCH 29/65] new configs & todos --- .../tour-of-beam/frontend/lib/config.dart | 21 +++++++------------ .../frontend/lib/firebase_options.dart | 12 +++++------ learning/tour-of-beam/frontend/lib/main.dart | 1 + .../lib/pages/tour/widgets/content.dart | 1 + 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/config.dart b/learning/tour-of-beam/frontend/lib/config.dart index b7ed542e1b05..27dff083af8f 100644 --- a/learning/tour-of-beam/frontend/lib/config.dart +++ b/learning/tour-of-beam/frontend/lib/config.dart @@ -18,22 +18,15 @@ // TODO(alexeyinkin): Generate this file on deployment. -const _cloudFunctionsProjectRegion = 'us-central1'; -const _cloudFunctionsProjectId = 'tour-of-beam-2'; +const _cloudFunctionsProjectRegion = 'us-east1'; +const _cloudFunctionsProjectId = 'astest-369409'; const cloudFunctionsBaseUrl = 'https://' '$_cloudFunctionsProjectRegion-$_cloudFunctionsProjectId' '.cloudfunctions.net'; - // Copied from Playground's config.g.dart - const String kAnalyticsUA = 'UA-73650088-2'; -const String kApiClientURL = - 'https://backend-router-beta-dot-apache-beam-testing.appspot.com'; -const String kApiJavaClientURL = - 'https://backend-java-beta-dot-apache-beam-testing.appspot.com'; -const String kApiGoClientURL = - 'https://backend-go-beta-dot-apache-beam-testing.appspot.com'; -const String kApiPythonClientURL = - 'https://backend-python-beta-dot-apache-beam-testing.appspot.com'; -const String kApiScioClientURL = - 'https://backend-scio-beta-dot-apache-beam-testing.appspot.com'; +const String kApiClientURL = 'https://router.dev-playground.online/'; +const String kApiJavaClientURL = 'https://java.dev-playground.online/'; +const String kApiGoClientURL = 'https://go.dev-playground.online/'; +const String kApiPythonClientURL = 'https://python.dev-playground.online/'; +const String kApiScioClientURL = 'https://scio.dev-playground.online/'; diff --git a/learning/tour-of-beam/frontend/lib/firebase_options.dart b/learning/tour-of-beam/frontend/lib/firebase_options.dart index b3cefabf2d39..e2a871d637b3 100644 --- a/learning/tour-of-beam/frontend/lib/firebase_options.dart +++ b/learning/tour-of-beam/frontend/lib/firebase_options.dart @@ -53,11 +53,11 @@ class DefaultFirebaseOptions { } static const FirebaseOptions web = FirebaseOptions( - apiKey: 'AIzaSyD_Nj83s6-EJ_2QxsOzA0W9hULuhwe5FXk', - appId: '1:358160552171:web:39fba96946d1c6c6c12eae', - messagingSenderId: '358160552171', - projectId: 'sandbox-playground-002', - authDomain: 'sandbox-playground-002.firebaseapp.com', - storageBucket: 'sandbox-playground-002.appspot.com', + apiKey: 'AIzaSyBtAreurqJ5D4IK6cNisZh5dnDRKljbJAw', + authDomain: 'astest-369409.firebaseapp.com', + projectId: 'astest-369409', + storageBucket: 'astest-369409.appspot.com', + messagingSenderId: '534850967604', + appId: '1:534850967604:web:55c6af8da7940df1ddd261', ); } diff --git a/learning/tour-of-beam/frontend/lib/main.dart b/learning/tour-of-beam/frontend/lib/main.dart index 7139c0b42f92..d87497c2de03 100644 --- a/learning/tour-of-beam/frontend/lib/main.dart +++ b/learning/tour-of-beam/frontend/lib/main.dart @@ -31,6 +31,7 @@ import 'firebase_options.dart'; import 'locator.dart'; import 'router/route_information_parser.dart'; +// TODO(nausharipov): fix "ScrollController not attached to any scroll views." void main() async { await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart index a67c033722f3..daf196658b68 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart @@ -128,6 +128,7 @@ class _CompleteUnitButton extends StatelessWidget { ), ), ), + // TODO(nausharipov): add loading onPressed: isDisabled ? null : tour.currentUnitController.completeUnit, child: const Text( From 64965a1e1f49f0240b4e27a387aad099caade1b2 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 24 Nov 2022 14:44:19 +0600 Subject: [PATCH 30/65] canCompleteCurrentUnit (#23692) --- .../frontend/lib/pages/tour/state.dart | 9 +++++---- .../frontend/lib/pages/tour/widgets/content.dart | 16 ++++++---------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 708856b769d7..2d188e44defc 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -35,6 +35,7 @@ import 'path.dart'; class TourNotifier extends ChangeNotifier with PageStateMixin { final ContentTreeController contentTreeController; final PlaygroundController playgroundController; + // TODO(nausharipov): avoid late? late UnitController currentUnitController; final _app = GetIt.instance.get(); final _auth = GetIt.instance.get(); @@ -66,10 +67,10 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { treeIds: contentTreeController.treeIds, ); - bool isCurrentUnitCompleted() { - return _userProgress.isUnitCompleted( - contentTreeController.currentNode?.id, - ); + bool canCompleteCurrentUnit() { + return _auth.isAuthenticated && + !currentUnitController.isCompleting && + !_userProgress.isUnitCompleted(contentTreeController.currentNode?.id); } UnitContentModel? get currentUnitContent => _currentUnitContent; diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart index daf196658b68..15c5cc5b0fa9 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart @@ -105,22 +105,18 @@ class _CompleteUnitButton extends StatelessWidget { Widget build(BuildContext context) { final themeData = Theme.of(context); final userProgress = GetIt.instance.get(); - final auth = GetIt.instance.get(); return AnimatedBuilder( animation: userProgress, builder: (context, child) { - final isDisabled = - !auth.isAuthenticated || tour.isCurrentUnitCompleted(); - return Flexible( child: OutlinedButton( style: OutlinedButton.styleFrom( foregroundColor: themeData.primaryColor, side: BorderSide( - color: isDisabled - ? themeData.disabledColor - : themeData.primaryColor, + color: tour.canCompleteCurrentUnit() + ? themeData.primaryColor + : themeData.disabledColor, ), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all( @@ -128,9 +124,9 @@ class _CompleteUnitButton extends StatelessWidget { ), ), ), - // TODO(nausharipov): add loading - onPressed: - isDisabled ? null : tour.currentUnitController.completeUnit, + onPressed: tour.canCompleteCurrentUnit() + ? tour.currentUnitController.completeUnit + : null, child: const Text( 'pages.tour.completeUnit', overflow: TextOverflow.ellipsis, From 6d21e1ea3f0837616a185e4b1f0d48398799791d Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 24 Nov 2022 14:52:08 +0600 Subject: [PATCH 31/65] kOpenLoginOverlay (#23692) --- .../frontend/lib/components/functions.dart | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/learning/tour-of-beam/frontend/lib/components/functions.dart b/learning/tour-of-beam/frontend/lib/components/functions.dart index 562aa34b29d2..9721b0cb428c 100644 --- a/learning/tour-of-beam/frontend/lib/components/functions.dart +++ b/learning/tour-of-beam/frontend/lib/components/functions.dart @@ -1,3 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; @@ -5,7 +23,7 @@ import 'package:playground_components/playground_components.dart'; import 'login/content.dart'; import 'profile/user_menu.dart'; -void openLoginOverlay(BuildContext context, [User? user]) { +void kOpenLoginOverlay(BuildContext context, [User? user]) { final overlayCloser = PublicNotifier(); final overlay = OverlayEntry( builder: (context) { From 2c90ced90376df81d0989c233995320a73c7feb1 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 24 Nov 2022 14:55:05 +0600 Subject: [PATCH 32/65] login_overlay (#23692) --- .../frontend/lib/components/login/button.dart | 4 +- .../lib/components/login_overlay.dart | 49 +++++++++++++++++++ .../lib/components/profile/avatar.dart | 4 +- 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 learning/tour-of-beam/frontend/lib/components/login_overlay.dart diff --git a/learning/tour-of-beam/frontend/lib/components/login/button.dart b/learning/tour-of-beam/frontend/lib/components/login/button.dart index 1ba2ad19dc0f..ebd2faa07cc0 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/button.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/button.dart @@ -19,7 +19,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import '../functions.dart'; +import '../login_overlay.dart'; class LoginButton extends StatelessWidget { const LoginButton(); @@ -28,7 +28,7 @@ class LoginButton extends StatelessWidget { Widget build(BuildContext context) { return TextButton( onPressed: () { - openLoginOverlay(context); + kOpenLoginOverlay(context); }, child: const Text('ui.signIn').tr(), ); diff --git a/learning/tour-of-beam/frontend/lib/components/login_overlay.dart b/learning/tour-of-beam/frontend/lib/components/login_overlay.dart new file mode 100644 index 000000000000..9721b0cb428c --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/components/login_overlay.dart @@ -0,0 +1,49 @@ +/* + * 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:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:playground_components/playground_components.dart'; + +import 'login/content.dart'; +import 'profile/user_menu.dart'; + +void kOpenLoginOverlay(BuildContext context, [User? user]) { + final overlayCloser = PublicNotifier(); + final overlay = OverlayEntry( + builder: (context) { + return DismissibleOverlay( + close: overlayCloser.notifyPublic, + child: Positioned( + right: BeamSizes.size10, + top: BeamSizes.appBarHeight, + child: user == null + ? LoginContent( + onLoggedIn: overlayCloser.notifyPublic, + ) + : UserMenu( + onLoggedOut: overlayCloser.notifyPublic, + user: user, + ), + ), + ); + }, + ); + overlayCloser.addListener(overlay.remove); + Overlay.of(context)?.insert(overlay); +} diff --git a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart index 19fe698f3731..6218a81cdd13 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart @@ -21,7 +21,7 @@ import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; import '../../generated/assets.gen.dart'; -import '../functions.dart'; +import '../login_overlay.dart'; class Avatar extends StatelessWidget { final User user; @@ -32,7 +32,7 @@ class Avatar extends StatelessWidget { final photoUrl = user.photoURL; return GestureDetector( onTap: () { - openLoginOverlay(context, user); + kOpenLoginOverlay(context, user); }, child: CircleAvatar( backgroundColor: BeamColors.white, From 6ed38acb2beb4b960eb7a77da1282683e2805bc0 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 24 Nov 2022 15:14:07 +0600 Subject: [PATCH 33/65] unused import (#23692) --- .../tour-of-beam/frontend/lib/pages/tour/widgets/content.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart index 15c5cc5b0fa9..3f7f447677ae 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart @@ -21,7 +21,6 @@ import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; -import '../../../auth/notifier.dart'; import '../../../cache/user_progress.dart'; import '../../../constants/sizes.dart'; import '../state.dart'; From adbdeb6eec823178d487a3a3b3bba07ceda6efa9 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 24 Nov 2022 15:15:57 +0600 Subject: [PATCH 34/65] deleted file (#23692) --- .../frontend/lib/components/functions.dart | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 learning/tour-of-beam/frontend/lib/components/functions.dart diff --git a/learning/tour-of-beam/frontend/lib/components/functions.dart b/learning/tour-of-beam/frontend/lib/components/functions.dart deleted file mode 100644 index 9721b0cb428c..000000000000 --- a/learning/tour-of-beam/frontend/lib/components/functions.dart +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:flutter/material.dart'; -import 'package:playground_components/playground_components.dart'; - -import 'login/content.dart'; -import 'profile/user_menu.dart'; - -void kOpenLoginOverlay(BuildContext context, [User? user]) { - final overlayCloser = PublicNotifier(); - final overlay = OverlayEntry( - builder: (context) { - return DismissibleOverlay( - close: overlayCloser.notifyPublic, - child: Positioned( - right: BeamSizes.size10, - top: BeamSizes.appBarHeight, - child: user == null - ? LoginContent( - onLoggedIn: overlayCloser.notifyPublic, - ) - : UserMenu( - onLoggedOut: overlayCloser.notifyPublic, - user: user, - ), - ), - ); - }, - ); - overlayCloser.addListener(overlay.remove); - Overlay.of(context)?.insert(overlay); -} From c2f74a59ed6a364d04a9cb0d11ea0e1f0ce5ffbf Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Sun, 27 Nov 2022 21:05:49 +0600 Subject: [PATCH 35/65] review comments (2) --- .../frontend/lib/auth/notifier.dart | 12 +- .../frontend/lib/cache/user_progress.dart | 19 +-- .../lib/components/builders/content_tree.dart | 6 +- .../lib/components/builders/sdks.dart | 6 +- .../frontend/lib/components/login/button.dart | 11 +- .../lib/components/login/content.dart | 4 +- .../{login_overlay.dart => open_overlay.dart} | 24 ++-- .../lib/components/profile/avatar.dart | 13 +- .../lib/components/profile/user_menu.dart | 16 +-- .../frontend/lib/components/scaffold.dart | 29 +++-- learning/tour-of-beam/frontend/lib/main.dart | 2 +- .../frontend/lib/models/user_progress.dart | 4 +- .../pages/tour/controllers/content_tree.dart | 8 +- .../frontend/lib/pages/tour/screen.dart | 26 ++-- .../frontend/lib/pages/tour/state.dart | 46 +++---- .../tour/widgets/complete_unit_button.dart | 48 +++++++ .../lib/pages/tour/widgets/content.dart | 62 ++------- .../lib/pages/tour/widgets/content_tree.dart | 1 + .../lib/pages/tour/widgets/group_title.dart | 10 +- .../frontend/lib/pages/tour/widgets/unit.dart | 6 +- .../frontend/lib/pages/welcome/screen.dart | 38 +++--- .../client/cloud_functions_client.dart | 2 +- .../frontend/lib/repositories/exception.dart | 33 ----- .../frontend/lib/repositories/repository.dart | 121 ------------------ 24 files changed, 207 insertions(+), 340 deletions(-) rename learning/tour-of-beam/frontend/lib/components/{login_overlay.dart => open_overlay.dart} (67%) create mode 100644 learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart delete mode 100644 learning/tour-of-beam/frontend/lib/repositories/exception.dart delete mode 100644 learning/tour-of-beam/frontend/lib/repositories/repository.dart diff --git a/learning/tour-of-beam/frontend/lib/auth/notifier.dart b/learning/tour-of-beam/frontend/lib/auth/notifier.dart index a53225589362..fa48a364355a 100644 --- a/learning/tour-of-beam/frontend/lib/auth/notifier.dart +++ b/learning/tour-of-beam/frontend/lib/auth/notifier.dart @@ -23,27 +23,27 @@ import 'package:flutter/material.dart'; import 'method.dart'; class AuthNotifier extends ChangeNotifier { - final _firebase = FirebaseAuth.instance; final _authProviders = UnmodifiableAuthMethodMap( google: GoogleAuthProvider(), github: GithubAuthProvider(), ); AuthNotifier() { - _firebase.authStateChanges().listen((user) async { + FirebaseAuth.instance.authStateChanges().listen((user) async { notifyListeners(); }); } - bool get isAuthenticated => _firebase.currentUser != null; + bool get isAuthenticated => FirebaseAuth.instance.currentUser != null; - Future get token async => await _firebase.currentUser?.getIdToken(); + Future get token async => + await FirebaseAuth.instance.currentUser?.getIdToken(); Future logIn(AuthMethod authMethod) async { - await _firebase.signInWithPopup(_authProviders.get(authMethod)); + await FirebaseAuth.instance.signInWithPopup(_authProviders.get(authMethod)); } Future logOut() async { - await _firebase.signOut(); + await FirebaseAuth.instance.signOut(); } } diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart index dbbe2e381d52..50fc78c95dc7 100644 --- a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart @@ -27,7 +27,7 @@ import 'cache.dart'; class UserProgressCache extends Cache { UserProgressCache({required super.client}); - final _completedUnits = {}; + final _completedUnitIds = {}; Future?>? _future; bool isUnitCompleted(String? unitId) { @@ -35,28 +35,29 @@ class UserProgressCache extends Cache { } void updateCompletedUnits() { - _future = null; - getCompletedUnits(); + final sdkId = GetIt.instance.get().sdkId; + if (sdkId != null) { + unawaited(_loadCompletedUnits(sdkId)); + } } Set getCompletedUnits() { - final sdkId = GetIt.instance.get().sdkId; - if (sdkId != null && _future == null) { - unawaited(_loadCompletedUnits(sdkId)); + if (_future == null) { + updateCompletedUnits(); } - return _completedUnits; + return _completedUnitIds; } Future _loadCompletedUnits(String sdkId) async { _future = client.getUserProgress(sdkId); final result = await _future; - _completedUnits.clear(); + _completedUnitIds.clear(); if (result != null) { for (final unitProgress in result) { if (unitProgress.isCompleted) { - _completedUnits.add(unitProgress.id); + _completedUnitIds.add(unitProgress.unitId); } } } diff --git a/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart b/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart index d16bc23f9896..8ef706ead45a 100644 --- a/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart @@ -33,13 +33,13 @@ class ContentTreeBuilder extends StatelessWidget { @override Widget build(BuildContext context) { - final contentTree = GetIt.instance.get(); + final contentTreeCache = GetIt.instance.get(); return AnimatedBuilder( - animation: contentTree, + animation: contentTreeCache, builder: (context, child) => builder( context, - contentTree.getContentTree(sdkId), + contentTreeCache.getContentTree(sdkId), child, ), ); diff --git a/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart b/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart index 901e1be798d9..e6a5c6f97d35 100644 --- a/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart +++ b/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart @@ -31,11 +31,11 @@ class SdksBuilder extends StatelessWidget { @override Widget build(BuildContext context) { - final sdk = GetIt.instance.get(); + final sdkCache = GetIt.instance.get(); return AnimatedBuilder( - animation: sdk, - builder: (context, child) => builder(context, sdk.getSdks(), child), + animation: sdkCache, + builder: (context, child) => builder(context, sdkCache.getSdks(), child), ); } } diff --git a/learning/tour-of-beam/frontend/lib/components/login/button.dart b/learning/tour-of-beam/frontend/lib/components/login/button.dart index ebd2faa07cc0..2e56c26dcc51 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/button.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/button.dart @@ -18,8 +18,10 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:playground_components/playground_components.dart'; -import '../login_overlay.dart'; +import '../open_overlay.dart'; +import 'content.dart'; class LoginButton extends StatelessWidget { const LoginButton(); @@ -28,7 +30,12 @@ class LoginButton extends StatelessWidget { Widget build(BuildContext context) { return TextButton( onPressed: () { - kOpenLoginOverlay(context); + final closeNotifier = PublicNotifier(); + kOpenOverlay( + context, + closeNotifier, + LoginContent(onLoggedIn: closeNotifier.notifyPublic), + ); }, child: const Text('ui.signIn').tr(), ); diff --git a/learning/tour-of-beam/frontend/lib/components/login/content.dart b/learning/tour-of-beam/frontend/lib/components/login/content.dart index 4b097452b578..98bb42292597 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/content.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/content.dart @@ -101,7 +101,7 @@ class _BrandedLoginButtons extends StatelessWidget { @override Widget build(BuildContext context) { - final auth = GetIt.instance.get(); + final authNotifier = GetIt.instance.get(); final isLightTheme = Theme.of(context).brightness == Brightness.light; final textStyle = @@ -147,7 +147,7 @@ class _BrandedLoginButtons extends StatelessWidget { const SizedBox(height: BeamSizes.size16), ElevatedButton.icon( onPressed: () async { - await auth.logIn(AuthMethod.google); + await authNotifier.logIn(AuthMethod.google); onLoggedIn(); }, style: isLightTheme ? googleLightButtonStyle : darkButtonStyle, diff --git a/learning/tour-of-beam/frontend/lib/components/login_overlay.dart b/learning/tour-of-beam/frontend/lib/components/open_overlay.dart similarity index 67% rename from learning/tour-of-beam/frontend/lib/components/login_overlay.dart rename to learning/tour-of-beam/frontend/lib/components/open_overlay.dart index 9721b0cb428c..ed93fe881c24 100644 --- a/learning/tour-of-beam/frontend/lib/components/login_overlay.dart +++ b/learning/tour-of-beam/frontend/lib/components/open_overlay.dart @@ -16,34 +16,26 @@ * limitations under the License. */ -import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; -import 'login/content.dart'; -import 'profile/user_menu.dart'; - -void kOpenLoginOverlay(BuildContext context, [User? user]) { - final overlayCloser = PublicNotifier(); +void kOpenOverlay( + BuildContext context, + PublicNotifier closeNotifier, + Widget child, +) { final overlay = OverlayEntry( builder: (context) { return DismissibleOverlay( - close: overlayCloser.notifyPublic, + close: closeNotifier.notifyPublic, child: Positioned( right: BeamSizes.size10, top: BeamSizes.appBarHeight, - child: user == null - ? LoginContent( - onLoggedIn: overlayCloser.notifyPublic, - ) - : UserMenu( - onLoggedOut: overlayCloser.notifyPublic, - user: user, - ), + child: child, ), ); }, ); - overlayCloser.addListener(overlay.remove); + closeNotifier.addListener(overlay.remove); Overlay.of(context)?.insert(overlay); } diff --git a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart index 6218a81cdd13..8792d5c14744 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart @@ -21,7 +21,8 @@ import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; import '../../generated/assets.gen.dart'; -import '../login_overlay.dart'; +import '../open_overlay.dart'; +import 'user_menu.dart'; class Avatar extends StatelessWidget { final User user; @@ -32,7 +33,15 @@ class Avatar extends StatelessWidget { final photoUrl = user.photoURL; return GestureDetector( onTap: () { - kOpenLoginOverlay(context, user); + final closeNotifier = PublicNotifier(); + kOpenOverlay( + context, + closeNotifier, + UserMenu( + closeOverlayCallback: closeNotifier.notifyPublic, + user: user, + ), + ); }, child: CircleAvatar( backgroundColor: BeamColors.white, diff --git a/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart index 841c1b8277de..7b9428fae731 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart @@ -28,11 +28,11 @@ import '../../constants/sizes.dart'; import '../../generated/assets.gen.dart'; class UserMenu extends StatelessWidget { - final VoidCallback onLoggedOut; + final VoidCallback closeOverlayCallback; final User user; const UserMenu({ - required this.onLoggedOut, + required this.closeOverlayCallback, required this.user, }); @@ -45,7 +45,7 @@ class UserMenu extends StatelessWidget { _Info(user: user), const BeamDivider(), _Buttons( - closeOverlay: onLoggedOut, + closeOverlayCallback: closeOverlayCallback, ), ], ), @@ -105,15 +105,15 @@ class _Info extends StatelessWidget { } class _Buttons extends StatelessWidget { - final VoidCallback closeOverlay; + final VoidCallback closeOverlayCallback; const _Buttons({ - required this.closeOverlay, + required this.closeOverlayCallback, }); @override Widget build(BuildContext context) { - final auth = GetIt.instance.get(); + final authNotifier = GetIt.instance.get(); return Column( children: [ @@ -132,8 +132,8 @@ class _Buttons extends StatelessWidget { const BeamDivider(), _IconLabel( onTap: () async { - await auth.logOut(); - closeOverlay(); + await authNotifier.logOut(); + closeOverlayCallback(); }, iconPath: Assets.svg.profileLogout, label: 'ui.signOut'.tr(), diff --git a/learning/tour-of-beam/frontend/lib/components/scaffold.dart b/learning/tour-of-beam/frontend/lib/components/scaffold.dart index 49bd2f660639..007e6398ecca 100644 --- a/learning/tour-of-beam/frontend/lib/components/scaffold.dart +++ b/learning/tour-of-beam/frontend/lib/components/scaffold.dart @@ -68,8 +68,10 @@ class _Profile extends StatelessWidget { Widget build(BuildContext context) { return StreamBuilder( stream: FirebaseAuth.instance.userChanges(), - builder: (context, user) => - user.hasData ? Avatar(user: user.data!) : const LoginButton(), + builder: (context, snapshot) { + final user = snapshot.data; + return user == null ? const LoginButton() : Avatar(user: user); + }, ); } } @@ -93,17 +95,20 @@ class _SdkSelector extends StatelessWidget { @override Widget build(BuildContext context) { - final app = GetIt.instance.get(); + final appNotifier = GetIt.instance.get(); return AnimatedBuilder( - animation: app, - builder: (context, child) => app.sdkId == null - ? Container() - : SdkDropdown( - sdkId: app.sdkId!, - onChanged: (sdkId) { - app.sdkId = sdkId; - }, - ), + animation: appNotifier, + builder: (context, child) { + final sdkId = appNotifier.sdkId; + return sdkId == null + ? Container() + : SdkDropdown( + sdkId: sdkId, + onChanged: (value) { + appNotifier.sdkId = value; + }, + ); + }, ); } } diff --git a/learning/tour-of-beam/frontend/lib/main.dart b/learning/tour-of-beam/frontend/lib/main.dart index d87497c2de03..7a51f84de79c 100644 --- a/learning/tour-of-beam/frontend/lib/main.dart +++ b/learning/tour-of-beam/frontend/lib/main.dart @@ -31,7 +31,7 @@ import 'firebase_options.dart'; import 'locator.dart'; import 'router/route_information_parser.dart'; -// TODO(nausharipov): fix "ScrollController not attached to any scroll views." +// TODO(nausharipov): reproduce "ScrollController not attached to any scroll views." void main() async { await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, diff --git a/learning/tour-of-beam/frontend/lib/models/user_progress.dart b/learning/tour-of-beam/frontend/lib/models/user_progress.dart index b1176820d34f..b2d40823c920 100644 --- a/learning/tour-of-beam/frontend/lib/models/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/models/user_progress.dart @@ -22,11 +22,11 @@ part 'user_progress.g.dart'; @JsonSerializable(createToJson: false) class UserProgressModel { - final String id; + final String unitId; final bool isCompleted; const UserProgressModel({ - required this.id, + required this.unitId, required this.isCompleted, }); diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart index a1a28ef5eec7..bcdb686a10b7 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart @@ -30,7 +30,7 @@ class ContentTreeController extends ChangeNotifier { List _treeIds; // TODO(nausharipov): non-nullable currentNode? NodeModel? _currentNode; - final _contentTree = GetIt.instance.get(); + final _contentTreeCache = GetIt.instance.get(); final _expandedIds = {}; Set get expandedIds => _expandedIds; @@ -42,7 +42,7 @@ class ContentTreeController extends ChangeNotifier { _treeIds = initialTreeIds { _expandedIds.addAll(initialTreeIds); - _contentTree.addListener(_onContentTreeCacheChange); + _contentTreeCache.addListener(_onContentTreeCacheChange); _onContentTreeCacheChange(); } @@ -98,7 +98,7 @@ class ContentTreeController extends ChangeNotifier { } void _onContentTreeCacheChange() { - final contentTree = _contentTree.getContentTree(_sdkId); + final contentTree = _contentTreeCache.getContentTree(_sdkId); if (contentTree == null) { return; } @@ -112,7 +112,7 @@ class ContentTreeController extends ChangeNotifier { @override void dispose() { - _contentTree.removeListener(_onContentTreeCacheChange); + _contentTreeCache.removeListener(_onContentTreeCacheChange); super.dispose(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart index 3557111c0f76..a73d68efc4b2 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart @@ -27,37 +27,37 @@ import 'widgets/content_tree.dart'; import 'widgets/playground_demo.dart'; class TourScreen extends StatelessWidget { - final TourNotifier notifier; + final TourNotifier tourNotifier; - const TourScreen(this.notifier); + const TourScreen(this.tourNotifier); @override Widget build(BuildContext context) { return TobScaffold( child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns - ? _WideTour(notifier) - : _NarrowTour(notifier), + ? _WideTour(tourNotifier) + : _NarrowTour(tourNotifier), ); } } class _WideTour extends StatelessWidget { - final TourNotifier notifier; + final TourNotifier tourNotifier; - const _WideTour(this.notifier); + const _WideTour(this.tourNotifier); @override Widget build(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ContentTreeWidget(controller: notifier.contentTreeController), + ContentTreeWidget(controller: tourNotifier.contentTreeController), Expanded( child: SplitView( direction: Axis.horizontal, - first: ContentWidget(notifier), + first: ContentWidget(tourNotifier), second: PlaygroundDemoWidget( - playgroundController: notifier.playgroundController, + playgroundController: tourNotifier.playgroundController, ), ), ), @@ -67,9 +67,9 @@ class _WideTour extends StatelessWidget { } class _NarrowTour extends StatelessWidget { - final TourNotifier notifier; + final TourNotifier tourNotifier; - const _NarrowTour(this.notifier); + const _NarrowTour(this.tourNotifier); @override Widget build(BuildContext context) { @@ -79,8 +79,8 @@ class _NarrowTour extends StatelessWidget { Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ContentTreeWidget(controller: notifier.contentTreeController), - Expanded(child: ContentWidget(notifier)), + ContentTreeWidget(controller: tourNotifier.contentTreeController), + Expanded(child: ContentWidget(tourNotifier)), ], ), DecoratedBox( diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 2d188e44defc..83718744e6fe 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -36,11 +36,11 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { final ContentTreeController contentTreeController; final PlaygroundController playgroundController; // TODO(nausharipov): avoid late? - late UnitController currentUnitController; - final _app = GetIt.instance.get(); - final _auth = GetIt.instance.get(); - final _unitContent = GetIt.instance.get(); - final _userProgress = GetIt.instance.get(); + UnitController? currentUnitController; + final _appNotifier = GetIt.instance.get(); + final _authNotifier = GetIt.instance.get(); + final _unitContentCache = GetIt.instance.get(); + final _userProgressCache = GetIt.instance.get(); UnitContentModel? _currentUnitContent; TourNotifier({ @@ -52,10 +52,9 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { ), playgroundController = _createPlaygroundController(initialSdkId) { contentTreeController.addListener(_onUnitChanged); - _unitContent.addListener(_onUnitChanged); - _app.addListener(_onAppNotifierChanged); - _app.addListener(_onUserProgressChanged); - _auth.addListener(_onUserProgressChanged); + _unitContentCache.addListener(_onUnitChanged); + _appNotifier.addListener(_onAppNotifierChanged); + _authNotifier.addListener(_onUserProgressChanged); _onUnitChanged(); } @@ -68,14 +67,16 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { ); bool canCompleteCurrentUnit() { - return _auth.isAuthenticated && - !currentUnitController.isCompleting && - !_userProgress.isUnitCompleted(contentTreeController.currentNode?.id); + return _authNotifier.isAuthenticated && + // TODO(nausharipov): is completing + // !currentUnitController.isCompleting && + !_userProgressCache + .isUnitCompleted(contentTreeController.currentNode?.id); } UnitContentModel? get currentUnitContent => _currentUnitContent; - void _setCurrentUnitController(String sdkId, String unitId) { + void _createCurrentUnitController(String sdkId, String unitId) { currentUnitController = UnitController( unitId: unitId, sdkId: sdkId, @@ -83,14 +84,15 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { } void _onUserProgressChanged() { - _userProgress.updateCompletedUnits(); + _userProgressCache.updateCompletedUnits(); } void _onAppNotifierChanged() { - final sdkId = _app.sdkId; + final sdkId = _appNotifier.sdkId; if (sdkId != null) { playgroundController.setSdk(Sdk.parseOrCreate(sdkId)); contentTreeController.sdkId = sdkId; + _onUserProgressChanged(); } } @@ -98,11 +100,11 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { emitPathChanged(); final currentNode = contentTreeController.currentNode; if (currentNode is UnitModel) { - final content = _unitContent.getUnitContent( + final content = _unitContentCache.getUnitContent( contentTreeController.sdkId, currentNode.id, ); - _setCurrentUnitController(contentTreeController.sdkId, currentNode.id); + _createCurrentUnitController(contentTreeController.sdkId, currentNode.id); _setCurrentUnitContent(content); } else { _emptyPlayground(); @@ -189,12 +191,12 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { @override void dispose() { - _unitContent.removeListener(_onUnitChanged); + _unitContentCache.removeListener(_onUnitChanged); contentTreeController.removeListener(_onUnitChanged); - currentUnitController.removeListener(_onUserProgressChanged); - _app.removeListener(_onUserProgressChanged); - _app.removeListener(_onAppNotifierChanged); - _auth.removeListener(_onUserProgressChanged); + currentUnitController?.removeListener(_onUserProgressChanged); + _appNotifier.removeListener(_onUserProgressChanged); + _appNotifier.removeListener(_onAppNotifierChanged); + _authNotifier.removeListener(_onUserProgressChanged); super.dispose(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart new file mode 100644 index 000000000000..a570b3d6649b --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart @@ -0,0 +1,48 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import 'package:playground_components/playground_components.dart'; + +import '../../../cache/user_progress.dart'; +import '../state.dart'; + +class CompleteUnitButton extends StatelessWidget { + final TourNotifier tourNotifier; + const CompleteUnitButton(this.tourNotifier); + + @override + Widget build(BuildContext context) { + final themeData = Theme.of(context); + final userProgressCache = GetIt.instance.get(); + + return AnimatedBuilder( + animation: userProgressCache, + builder: (context, child) { + return Flexible( + child: OutlinedButton( + style: OutlinedButton.styleFrom( + foregroundColor: themeData.primaryColor, + side: BorderSide( + color: tourNotifier.canCompleteCurrentUnit() + ? themeData.primaryColor + : themeData.disabledColor, + ), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(BeamSizes.size4), + ), + ), + ), + onPressed: tourNotifier.canCompleteCurrentUnit() + ? tourNotifier.currentUnitController?.completeUnit + : null, + child: const Text( + 'pages.tour.completeUnit', + overflow: TextOverflow.ellipsis, + ).tr(), + ), + ); + }, + ); + } +} diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart index 3f7f447677ae..8677d4362d9d 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart @@ -16,20 +16,18 @@ * limitations under the License. */ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; -import '../../../cache/user_progress.dart'; import '../../../constants/sizes.dart'; import '../state.dart'; +import 'complete_unit_button.dart'; import 'unit_content.dart'; class ContentWidget extends StatelessWidget { - final TourNotifier notifier; + final TourNotifier tourNotifier; - const ContentWidget(this.notifier); + const ContentWidget(this.tourNotifier); @override Widget build(BuildContext context) { @@ -46,9 +44,9 @@ class ContentWidget extends StatelessWidget { ), ), child: AnimatedBuilder( - animation: notifier, + animation: tourNotifier, builder: (context, child) { - final currentUnitContent = notifier.currentUnitContent; + final currentUnitContent = tourNotifier.currentUnitContent; return Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -58,7 +56,7 @@ class ContentWidget extends StatelessWidget { ? Container() : UnitContentWidget(unitContent: currentUnitContent), ), - _ContentFooter(notifier), + _ContentFooter(tourNotifier), ], ); }, @@ -68,8 +66,8 @@ class ContentWidget extends StatelessWidget { } class _ContentFooter extends StatelessWidget { - final TourNotifier notifier; - const _ContentFooter(this.notifier); + final TourNotifier tourNotifier; + const _ContentFooter(this.tourNotifier); @override Widget build(BuildContext context) { @@ -88,51 +86,9 @@ class _ContentFooter extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - _CompleteUnitButton(notifier), + CompleteUnitButton(tourNotifier), ], ), ); } } - -class _CompleteUnitButton extends StatelessWidget { - // TODO(nausharipov): rename notifier to tour everywhere? - final TourNotifier tour; - const _CompleteUnitButton(this.tour); - - @override - Widget build(BuildContext context) { - final themeData = Theme.of(context); - final userProgress = GetIt.instance.get(); - - return AnimatedBuilder( - animation: userProgress, - builder: (context, child) { - return Flexible( - child: OutlinedButton( - style: OutlinedButton.styleFrom( - foregroundColor: themeData.primaryColor, - side: BorderSide( - color: tour.canCompleteCurrentUnit() - ? themeData.primaryColor - : themeData.disabledColor, - ), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(BeamSizes.size4), - ), - ), - ), - onPressed: tour.canCompleteCurrentUnit() - ? tour.currentUnitController.completeUnit - : null, - child: const Text( - 'pages.tour.completeUnit', - overflow: TextOverflow.ellipsis, - ).tr(), - ), - ); - }, - ); - } -} diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content_tree.dart index d6cf5fc14032..a40f14d35c60 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content_tree.dart @@ -24,6 +24,7 @@ import '../controllers/content_tree.dart'; import 'content_tree_title.dart'; import 'module.dart'; +// TODO(nausharipov): make it collapsible class ContentTreeWidget extends StatelessWidget { final ContentTreeController controller; diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart index 271e775ea46a..be6c937b8aa8 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart @@ -57,14 +57,14 @@ class _GroupProgressIndicator extends StatelessWidget { @override Widget build(BuildContext context) { - final userProgress = GetIt.instance.get(); + final userProgressCache = GetIt.instance.get(); return AnimatedBuilder( - animation: userProgress, + animation: userProgressCache, builder: (context, child) { final progress = _getGroupProgress( group.nodes, - userProgress.getCompletedUnits(), + userProgressCache.getCompletedUnits(), ); if (progress == 1) { @@ -95,8 +95,8 @@ class _GroupProgressIndicator extends StatelessWidget { List groupNodes, Set completedUnits, ) { - var completed = 0; - var total = 0; + int completed = 0; + int total = 0; void countNodes(List nodes) { for (final node in nodes) { diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart index 0d537676a8b9..0b693d701022 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart @@ -36,7 +36,7 @@ class UnitWidget extends StatelessWidget { @override Widget build(BuildContext context) { - final userProgress = GetIt.instance.get(); + final userProgressCache = GetIt.instance.get(); return AnimatedBuilder( animation: contentTreeController, @@ -54,9 +54,9 @@ class UnitWidget extends StatelessWidget { child: Row( children: [ AnimatedBuilder( - animation: userProgress, + animation: userProgressCache, builder: (context, child) => CompletenessIndicator( - isCompleted: userProgress.isUnitCompleted(unit.id), + isCompleted: userProgressCache.isUnitCompleted(unit.id), isSelected: isSelected, ), ), diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart index ebb594ea9044..621843f4ec7f 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart @@ -37,26 +37,26 @@ import '../tour/page.dart'; import 'state.dart'; class WelcomeScreen extends StatelessWidget { - final WelcomeNotifier notifier; + final WelcomeNotifier welcomeNotifier; - const WelcomeScreen(this.notifier); + const WelcomeScreen(this.welcomeNotifier); @override Widget build(BuildContext context) { return TobScaffold( child: SingleChildScrollView( child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns - ? _WideWelcome(notifier) - : _NarrowWelcome(notifier), + ? _WideWelcome(welcomeNotifier) + : _NarrowWelcome(welcomeNotifier), ), ); } } class _WideWelcome extends StatelessWidget { - final WelcomeNotifier notifier; + final WelcomeNotifier welcomeNotifier; - const _WideWelcome(this.notifier); + const _WideWelcome(this.welcomeNotifier); @override Widget build(BuildContext context) { @@ -77,9 +77,9 @@ class _WideWelcome extends StatelessWidget { } class _NarrowWelcome extends StatelessWidget { - final WelcomeNotifier notifier; + final WelcomeNotifier welcomeNotifier; - const _NarrowWelcome(this.notifier); + const _NarrowWelcome(this.welcomeNotifier); @override Widget build(BuildContext context) { @@ -99,7 +99,7 @@ class _SdkSelection extends StatelessWidget { @override Widget build(BuildContext context) { - final app = GetIt.instance.get(); + final appNotifier = GetIt.instance.get(); return Container( constraints: BoxConstraints( minHeight: MediaQuery.of(context).size.height - @@ -132,13 +132,13 @@ class _SdkSelection extends StatelessWidget { } return AnimatedBuilder( - animation: app, + animation: appNotifier, builder: (context, child) => _SdkButtons( sdks: sdks, - sdkId: app.sdkId, - setSdkId: (v) => app.sdkId = v, + sdkId: appNotifier.sdkId, + setSdkId: (v) => appNotifier.sdkId = v, onStartPressed: () { - _startTour(app.sdkId); + _startTour(appNotifier.sdkId); }, ), ); @@ -165,11 +165,11 @@ class _TourSummary extends StatelessWidget { @override Widget build(BuildContext context) { - final app = GetIt.instance.get(); + final appNotifier = GetIt.instance.get(); return AnimatedBuilder( - animation: app, + animation: appNotifier, builder: (context, child) { - final sdkId = app.sdkId; + final sdkId = appNotifier.sdkId; if (sdkId == null) { return Container(); } @@ -235,9 +235,9 @@ class _IntroTextBody extends StatelessWidget { @override Widget build(BuildContext context) { - final auth = GetIt.instance.get(); + final authNotifier = GetIt.instance.get(); return AnimatedBuilder( - animation: auth, + animation: authNotifier, builder: (context, child) => RichText( text: TextSpan( style: Theme.of(context).textTheme.bodyLarge, @@ -245,7 +245,7 @@ class _IntroTextBody extends StatelessWidget { TextSpan( text: 'pages.welcome.ifSaveProgress'.tr(), ), - if (auth.isAuthenticated) + if (authNotifier.isAuthenticated) TextSpan( text: 'pages.welcome.signIn'.tr(), ) diff --git a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart index c9b53295b2d2..ccdaa92913ff 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart @@ -32,7 +32,7 @@ import '../models/get_sdks_response.dart'; import '../models/get_user_progress_response.dart'; import 'client.dart'; -// TODO(nausharipov): add abstraction layers for calling API methods +// TODO(nausharipov): add repository and handle exceptions class CloudFunctionsTobClient extends TobClient { @override Future getSdks() async { diff --git a/learning/tour-of-beam/frontend/lib/repositories/exception.dart b/learning/tour-of-beam/frontend/lib/repositories/exception.dart deleted file mode 100644 index 90595afcfc49..000000000000 --- a/learning/tour-of-beam/frontend/lib/repositories/exception.dart +++ /dev/null @@ -1,33 +0,0 @@ -abstract class APIException implements Exception { - final String message; - const APIException(this.message); - - @override - String toString() => message; -} - -class APIGenericException extends APIException { - static const String type = 'API Call Failed'; - - const APIGenericException(String message) : super('$type: $message'); -} - -class APIAuthenticationException extends APIException { - static const String type = 'Authentication Failed'; - - const APIAuthenticationException(String message) : super('$type: $message'); -} - -class APIInternalServerException extends APIException { - static const String type = 'Internal Server Error'; - - const APIInternalServerException() - : super('$type: Something is wrong on backend side'); -} - -class InternalFrontendException extends APIException { - static const String type = 'Internal Error'; - - const InternalFrontendException() - : super('$type: Something is wrong on frontend side'); -} diff --git a/learning/tour-of-beam/frontend/lib/repositories/repository.dart b/learning/tour-of-beam/frontend/lib/repositories/repository.dart deleted file mode 100644 index 618974c7ba1b..000000000000 --- a/learning/tour-of-beam/frontend/lib/repositories/repository.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'dart:convert' as convert; - -import 'package:flutter/foundation.dart' show mustCallSuper; -import 'package:http/http.dart' as http; - -import '../config.dart'; -import 'exception.dart'; - -class APIRepository { - static const String _authority = cloudFunctionsBaseUrl; - - final String _basePath; - final Map _defaultHeaders; - - APIRepository({ - required String basePath, - Map defaultHeaders = const {}, - }) : _basePath = basePath, - _defaultHeaders = Map.unmodifiable(defaultHeaders); - - // A bit of wrapping for specifying mock client in tests. - http.Client _createClient() => http.Client(); - - Future _withClient(Future Function(http.Client) fn) async { - final client = _createClient(); - try { - return await fn(client); - } finally { - client.close(); - } - } - - /// Getting headers might be asynchronous, because a token - /// might need to be refreshed. - @mustCallSuper - Future> get headers async { - final headers = {'Content-Type': 'application/json; charset=utf-8'}; - return headers..addAll(_defaultHeaders); - } - - /// Sends a low-level get request. - Future get( - String path, { - Map? queryParams, - Map extraHeaders = const {}, - }) async { - final uri = Uri.https(_authority, _basePath + path, queryParams); - - final response = await _withClient( - (client) async => client.get( - uri, - headers: (await headers)..addAll(extraHeaders), - ), - ); - return _decode(response); - } - - /// Sends a low-level post request. - Future post( - String path, - Map data, { - Map? queryParams, - Map extraHeaders = const {}, - }) async { - final uri = Uri.https(_authority, _basePath + path, queryParams); - - final response = await _withClient( - (client) async => client.post( - uri, - headers: (await headers)..addAll(extraHeaders), - body: convert.jsonEncode(data), - ), - ); - return _decode(response); - } - - void _handleError(http.Response response) { - if (response.statusCode == 500) { - throw const APIInternalServerException(); - } - - final utf8Body = convert.utf8.decode(response.bodyBytes); - try { - final jsonResponse = convert.jsonDecode(utf8Body); - if (response.statusCode == 401) { - throw APIAuthenticationException(jsonResponse['message'] ?? utf8Body); - } - throw APIGenericException(jsonResponse['message'] ?? utf8Body); - } on FormatException { - throw APIGenericException(utf8Body); - } - } - - dynamic _decode(http.Response response) { - if (response.statusCode >= 200 && response.statusCode < 400) { - final utf8Body = convert.utf8.decode(response.bodyBytes); - if (utf8Body.isEmpty) { - return null; - } - try { - return convert.jsonDecode(utf8Body); - } on FormatException { - throw APIGenericException(utf8Body); - } - } - _handleError(response); - } -} - -class TestAPIRepository extends APIRepository { - final http.Client client; - - TestAPIRepository( - this.client, { - required super.basePath, - super.defaultHeaders, - }); - - @override - http.Client _createClient() => client; -} From a575717869b239f59374caf74f81db74191c3781 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 28 Nov 2022 12:41:44 +0600 Subject: [PATCH 36/65] deleted pubspec.lock --- learning/tour-of-beam/frontend/pubspec.lock | 1124 ----------------- .../playground_components/pubspec.lock | 941 -------------- 2 files changed, 2065 deletions(-) delete mode 100644 learning/tour-of-beam/frontend/pubspec.lock delete mode 100644 playground/frontend/playground_components/pubspec.lock diff --git a/learning/tour-of-beam/frontend/pubspec.lock b/learning/tour-of-beam/frontend/pubspec.lock deleted file mode 100644 index d0b74455a495..000000000000 --- a/learning/tour-of-beam/frontend/pubspec.lock +++ /dev/null @@ -1,1124 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - url: "https://pub.dartlang.org" - source: hosted - version: "46.0.0" - _flutterfire_internals: - dependency: transitive - description: - name: _flutterfire_internals - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.7" - aligned_dialog: - dependency: transitive - description: - name: aligned_dialog - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.6" - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.dartlang.org" - source: hosted - version: "4.6.0" - app_state: - dependency: "direct main" - description: - name: app_state - url: "https://pub.dartlang.org" - source: hosted - version: "0.8.1" - archive: - dependency: transitive - description: - name: archive - url: "https://pub.dartlang.org" - source: hosted - version: "3.3.0" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.1" - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.9.0" - autotrie: - dependency: transitive - description: - name: autotrie - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - build: - dependency: transitive - description: - name: build - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.0" - build_config: - dependency: transitive - description: - name: build_config - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - build_daemon: - dependency: transitive - description: - name: build_daemon - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.9" - build_runner: - dependency: "direct dev" - description: - name: build_runner - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.0" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - url: "https://pub.dartlang.org" - source: hosted - version: "7.2.3" - built_collection: - dependency: transitive - description: - name: built_collection - url: "https://pub.dartlang.org" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - url: "https://pub.dartlang.org" - source: hosted - version: "8.4.1" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - cloud_firestore_platform_interface: - dependency: transitive - description: - name: cloud_firestore_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "5.8.4" - cloud_firestore_web: - dependency: transitive - description: - name: cloud_firestore_web - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.4" - code_builder: - dependency: transitive - description: - name: code_builder - url: "https://pub.dartlang.org" - source: hosted - version: "4.2.0" - collection: - dependency: "direct main" - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.16.0" - color: - dependency: transitive - description: - name: color - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.2" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.2" - csv: - dependency: transitive - description: - name: csv - url: "https://pub.dartlang.org" - source: hosted - version: "5.0.1" - dart_style: - dependency: transitive - description: - name: dart_style - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.3" - dartx: - dependency: transitive - description: - name: dartx - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - easy_localization: - dependency: "direct main" - description: - name: easy_localization - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - easy_localization_ext: - dependency: "direct main" - description: - name: easy_localization_ext - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.1" - easy_localization_loader: - dependency: "direct main" - description: - name: easy_localization_loader - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - easy_logger: - dependency: transitive - description: - name: easy_logger - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.2" - enum_map: - dependency: "direct main" - description: - name: enum_map - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.1" - enum_map_gen: - dependency: "direct dev" - description: - name: enum_map_gen - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" - equatable: - dependency: "direct dev" - description: - name: equatable - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.5" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - ffi: - dependency: transitive - description: - name: ffi - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.2" - firebase_auth: - dependency: "direct main" - description: - name: firebase_auth - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.1" - firebase_auth_platform_interface: - dependency: transitive - description: - name: firebase_auth_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "6.11.1" - firebase_auth_web: - dependency: transitive - description: - name: firebase_auth_web - url: "https://pub.dartlang.org" - source: hosted - version: "5.1.1" - firebase_core: - dependency: "direct main" - description: - name: firebase_core - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - firebase_core_platform_interface: - dependency: transitive - description: - name: firebase_core_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "4.5.2" - firebase_core_web: - dependency: transitive - description: - name: firebase_core_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - fixnum: - dependency: transitive - description: - name: fixnum - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_code_editor: - dependency: transitive - description: - name: flutter_code_editor - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.8" - flutter_driver: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_gen_core: - dependency: transitive - description: - name: flutter_gen_core - url: "https://pub.dartlang.org" - source: hosted - version: "4.3.0" - flutter_gen_runner: - dependency: "direct dev" - description: - name: flutter_gen_runner - url: "https://pub.dartlang.org" - source: hosted - version: "4.3.0" - flutter_highlight: - dependency: transitive - description: - name: flutter_highlight - url: "https://pub.dartlang.org" - source: hosted - version: "0.7.0" - flutter_issue_108697_workaround: - dependency: transitive - description: - name: flutter_issue_108697_workaround - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.2" - flutter_localizations: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_markdown: - dependency: "direct main" - description: - name: flutter_markdown - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.12" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.3" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - get_it: - dependency: "direct main" - description: - name: get_it - url: "https://pub.dartlang.org" - source: hosted - version: "7.2.0" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - google_fonts: - dependency: "direct main" - description: - name: google_fonts - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - google_sign_in: - dependency: "direct main" - description: - name: google_sign_in - url: "https://pub.dartlang.org" - source: hosted - version: "5.4.2" - google_sign_in_android: - dependency: transitive - description: - name: google_sign_in_android - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.1" - google_sign_in_ios: - dependency: transitive - description: - name: google_sign_in_ios - url: "https://pub.dartlang.org" - source: hosted - version: "5.5.0" - google_sign_in_platform_interface: - dependency: transitive - description: - name: google_sign_in_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.0" - google_sign_in_web: - dependency: transitive - description: - name: google_sign_in_web - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.2" - googleapis_auth: - dependency: transitive - description: - name: googleapis_auth - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - graphs: - dependency: transitive - description: - name: graphs - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - grpc: - dependency: transitive - description: - name: grpc - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.2" - highlight: - dependency: transitive - description: - name: highlight - url: "https://pub.dartlang.org" - source: hosted - version: "0.7.0" - hive: - dependency: transitive - description: - name: hive - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.3" - http: - dependency: "direct main" - description: - name: http - url: "https://pub.dartlang.org" - source: hosted - version: "0.13.5" - http2: - dependency: transitive - description: - name: http2 - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - url: "https://pub.dartlang.org" - source: hosted - version: "3.2.1" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.1" - integration_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - intl: - dependency: transitive - description: - name: intl - url: "https://pub.dartlang.org" - source: hosted - version: "0.17.0" - io: - dependency: transitive - description: - name: io - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.4" - json_annotation: - dependency: "direct main" - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.7.0" - json_serializable: - dependency: "direct dev" - description: - name: json_serializable - url: "https://pub.dartlang.org" - source: hosted - version: "6.4.1" - linked_scroll_controller: - dependency: transitive - description: - name: linked_scroll_controller - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - markdown: - dependency: "direct main" - description: - name: markdown - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.12" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.5" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - mime: - dependency: transitive - description: - name: mime - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - nested: - dependency: transitive - description: - name: nested - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - package_config: - dependency: transitive - description: - name: package_config - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.2" - path_drawing: - dependency: transitive - description: - name: path_drawing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - path_parsing: - dependency: transitive - description: - name: path_parsing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - path_provider: - dependency: transitive - description: - name: path_provider - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.11" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.17" - path_provider_ios: - dependency: transitive - description: - name: path_provider_ios - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.11" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.7" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.6" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - petitparser: - dependency: transitive - description: - name: petitparser - url: "https://pub.dartlang.org" - source: hosted - version: "5.0.0" - platform: - dependency: transitive - description: - name: platform - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" - playground_components: - dependency: "direct main" - description: - path: "../../../playground/frontend/playground_components" - relative: true - source: path - version: "0.0.1" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.3" - pool: - dependency: transitive - description: - name: pool - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.1" - process: - dependency: transitive - description: - name: process - url: "https://pub.dartlang.org" - source: hosted - version: "4.2.4" - protobuf: - dependency: transitive - description: - name: protobuf - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - provider: - dependency: "direct main" - description: - name: provider - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.3" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" - quiver: - dependency: transitive - description: - name: quiver - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" - rxdart: - dependency: transitive - description: - name: rxdart - url: "https://pub.dartlang.org" - source: hosted - version: "0.27.5" - scrollable_positioned_list: - dependency: transitive - description: - name: scrollable_positioned_list - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.5" - shared_preferences: - dependency: "direct main" - description: - name: shared_preferences - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.15" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.12" - shared_preferences_ios: - dependency: transitive - description: - name: shared_preferences_ios - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - shared_preferences_macos: - dependency: transitive - description: - name: shared_preferences_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - shelf: - dependency: transitive - description: - name: shelf - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.2" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.5" - source_helper: - dependency: transitive - description: - name: source_helper - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.3" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.9.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - stream_transform: - dependency: transitive - description: - name: stream_transform - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - sync_http: - dependency: transitive - description: - name: sync_http - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.12" - time: - dependency: transitive - description: - name: time - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.2" - timing: - dependency: transitive - description: - name: timing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - total_lints: - dependency: "direct dev" - description: - name: total_lints - url: "https://pub.dartlang.org" - source: hosted - version: "2.17.4" - tuple: - dependency: transitive - description: - name: tuple - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.5" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.17" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.17" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.12" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - url_strategy: - dependency: "direct main" - description: - name: url_strategy - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.2" - vm_service: - dependency: transitive - description: - name: vm_service - url: "https://pub.dartlang.org" - source: hosted - version: "9.0.0" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.0" - webdriver: - dependency: transitive - description: - name: webdriver - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - win32: - dependency: transitive - description: - name: win32 - url: "https://pub.dartlang.org" - source: hosted - version: "2.7.0" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0+1" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "5.4.1" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.1" -sdks: - dart: ">=2.18.1 <3.0.0" - flutter: ">=3.3.2" diff --git a/playground/frontend/playground_components/pubspec.lock b/playground/frontend/playground_components/pubspec.lock deleted file mode 100644 index 31dfaefb36a0..000000000000 --- a/playground/frontend/playground_components/pubspec.lock +++ /dev/null @@ -1,941 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - url: "https://pub.dartlang.org" - source: hosted - version: "47.0.0" - aligned_dialog: - dependency: "direct main" - description: - name: aligned_dialog - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.6" - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.dartlang.org" - source: hosted - version: "4.7.0" - archive: - dependency: transitive - description: - name: archive - url: "https://pub.dartlang.org" - source: hosted - version: "3.3.4" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.1" - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.9.0" - autotrie: - dependency: transitive - description: - name: autotrie - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - build: - dependency: transitive - description: - name: build - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.1" - build_config: - dependency: transitive - description: - name: build_config - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - build_daemon: - dependency: transitive - description: - name: build_daemon - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.10" - build_runner: - dependency: "direct dev" - description: - name: build_runner - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.2" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - url: "https://pub.dartlang.org" - source: hosted - version: "7.2.7" - built_collection: - dependency: transitive - description: - name: built_collection - url: "https://pub.dartlang.org" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - url: "https://pub.dartlang.org" - source: hosted - version: "8.4.2" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - code_builder: - dependency: transitive - description: - name: code_builder - url: "https://pub.dartlang.org" - source: hosted - version: "4.3.0" - collection: - dependency: "direct main" - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.16.0" - color: - dependency: transitive - description: - name: color - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - connectivity_plus: - dependency: transitive - description: - name: connectivity_plus - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.9" - connectivity_plus_linux: - dependency: transitive - description: - name: connectivity_plus_linux - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - connectivity_plus_macos: - dependency: transitive - description: - name: connectivity_plus_macos - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.6" - connectivity_plus_platform_interface: - dependency: transitive - description: - name: connectivity_plus_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.3" - connectivity_plus_web: - dependency: transitive - description: - name: connectivity_plus_web - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.5" - connectivity_plus_windows: - dependency: transitive - description: - name: connectivity_plus_windows - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.2" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.1" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.2" - csv: - dependency: transitive - description: - name: csv - url: "https://pub.dartlang.org" - source: hosted - version: "5.0.1" - dart_style: - dependency: transitive - description: - name: dart_style - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.4" - dartx: - dependency: transitive - description: - name: dartx - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - dbus: - dependency: transitive - description: - name: dbus - url: "https://pub.dartlang.org" - source: hosted - version: "0.7.8" - easy_localization: - dependency: "direct main" - description: - name: easy_localization - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - easy_localization_ext: - dependency: "direct main" - description: - name: easy_localization_ext - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.1" - easy_localization_loader: - dependency: "direct main" - description: - name: easy_localization_loader - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1+1" - easy_logger: - dependency: transitive - description: - name: easy_logger - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.2" - equatable: - dependency: "direct main" - description: - name: equatable - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.5" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - ffi: - dependency: transitive - description: - name: ffi - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.4" - fixnum: - dependency: transitive - description: - name: fixnum - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_code_editor: - dependency: "direct main" - description: - name: flutter_code_editor - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.8" - flutter_gen_core: - dependency: transitive - description: - name: flutter_gen_core - url: "https://pub.dartlang.org" - source: hosted - version: "4.3.0" - flutter_gen_runner: - dependency: "direct dev" - description: - name: flutter_gen_runner - url: "https://pub.dartlang.org" - source: hosted - version: "4.3.0" - flutter_highlight: - dependency: transitive - description: - name: flutter_highlight - url: "https://pub.dartlang.org" - source: hosted - version: "0.7.0" - flutter_localizations: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_markdown: - dependency: "direct main" - description: - name: flutter_markdown - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.13" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.6" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - google_fonts: - dependency: "direct main" - description: - name: google_fonts - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - googleapis_auth: - dependency: transitive - description: - name: googleapis_auth - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - graphs: - dependency: transitive - description: - name: graphs - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.0" - grpc: - dependency: "direct main" - description: - name: grpc - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" - highlight: - dependency: "direct main" - description: - name: highlight - url: "https://pub.dartlang.org" - source: hosted - version: "0.7.0" - hive: - dependency: transitive - description: - name: hive - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.3" - http: - dependency: "direct main" - description: - name: http - url: "https://pub.dartlang.org" - source: hosted - version: "0.13.5" - http2: - dependency: transitive - description: - name: http2 - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - url: "https://pub.dartlang.org" - source: hosted - version: "3.2.1" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.2" - intl: - dependency: transitive - description: - name: intl - url: "https://pub.dartlang.org" - source: hosted - version: "0.17.0" - io: - dependency: transitive - description: - name: io - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.4" - json_annotation: - dependency: "direct main" - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.7.0" - json_serializable: - dependency: "direct dev" - description: - name: json_serializable - url: "https://pub.dartlang.org" - source: hosted - version: "6.5.4" - linked_scroll_controller: - dependency: transitive - description: - name: linked_scroll_controller - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - markdown: - dependency: transitive - description: - name: markdown - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.12" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.5" - meta: - dependency: "direct main" - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - mime: - dependency: transitive - description: - name: mime - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - mockito: - dependency: "direct dev" - description: - name: mockito - url: "https://pub.dartlang.org" - source: hosted - version: "5.2.0" - nested: - dependency: transitive - description: - name: nested - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - nm: - dependency: transitive - description: - name: nm - url: "https://pub.dartlang.org" - source: hosted - version: "0.5.0" - package_config: - dependency: transitive - description: - name: package_config - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.2" - path_drawing: - dependency: transitive - description: - name: path_drawing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - path_provider: - dependency: transitive - description: - name: path_provider - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.11" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.21" - path_provider_ios: - dependency: transitive - description: - name: path_provider_ios - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.11" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.7" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.6" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.5" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.3" - petitparser: - dependency: transitive - description: - name: petitparser - url: "https://pub.dartlang.org" - source: hosted - version: "5.1.0" - platform: - dependency: transitive - description: - name: platform - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.3" - pointycastle: - dependency: transitive - description: - name: pointycastle - url: "https://pub.dartlang.org" - source: hosted - version: "3.6.2" - pool: - dependency: transitive - description: - name: pool - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.1" - process: - dependency: transitive - description: - name: process - url: "https://pub.dartlang.org" - source: hosted - version: "4.2.4" - protobuf: - dependency: "direct main" - description: - name: protobuf - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - provider: - dependency: "direct main" - description: - name: provider - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.4" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.3" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" - scrollable_positioned_list: - dependency: transitive - description: - name: scrollable_positioned_list - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.5" - shared_preferences: - dependency: "direct main" - description: - name: shared_preferences - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.15" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.14" - shared_preferences_ios: - dependency: transitive - description: - name: shared_preferences_ios - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - shared_preferences_macos: - dependency: transitive - description: - name: shared_preferences_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - shelf: - dependency: transitive - description: - name: shelf - url: "https://pub.dartlang.org" - source: hosted - version: "1.4.0" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.6" - source_helper: - dependency: transitive - description: - name: source_helper - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.3" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.9.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - stream_transform: - dependency: transitive - description: - name: stream_transform - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.12" - time: - dependency: transitive - description: - name: time - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.3" - timing: - dependency: transitive - description: - name: timing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - total_lints: - dependency: "direct dev" - description: - name: total_lints - url: "https://pub.dartlang.org" - source: hosted - version: "2.18.0" - tuple: - dependency: transitive - description: - name: tuple - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.2" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.0" - win32: - dependency: transitive - description: - name: win32 - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.1" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0+2" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.0" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.1" -sdks: - dart: ">=2.18.1 <3.0.0" - flutter: ">=3.3.2" From 860780836bdf8cdbbcbe5952232abc3544effc9e Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 28 Nov 2022 12:44:52 +0600 Subject: [PATCH 37/65] pubspec.lock in gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 62f5a20d45e7..5a9e81a34dc3 100644 --- a/.gitignore +++ b/.gitignore @@ -127,6 +127,7 @@ website/www/yarn-error.log **/*.g.dart **/*.mocks.dart **/.packages +**/pubspec.lock # Ignore Beam Playground Terraform **/.terraform From 1bbc09279604dd2025ca6c93cfc85d2df9bece09 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 28 Nov 2022 14:36:25 +0600 Subject: [PATCH 38/65] comment fixes (3) --- .../frontend/lib/auth/notifier.dart | 7 ++-- .../frontend/lib/cache/user_progress.dart | 6 +-- .../frontend/lib/components/footer.dart | 6 ++- .../frontend/lib/components/login/button.dart | 3 +- .../lib/components/profile/avatar.dart | 13 +++--- .../tour-of-beam/frontend/lib/config.dart | 21 ++++++---- .../frontend/lib/pages/tour/state.dart | 42 +++++++++++-------- .../client/cloud_functions_client.dart | 4 +- .../lib/playground_components.dart | 1 + .../lib/src/widgets}/open_overlay.dart | 2 +- 10 files changed, 60 insertions(+), 45 deletions(-) rename {learning/tour-of-beam/frontend/lib/components => playground/frontend/playground_components/lib/src/widgets}/open_overlay.dart (98%) diff --git a/learning/tour-of-beam/frontend/lib/auth/notifier.dart b/learning/tour-of-beam/frontend/lib/auth/notifier.dart index fa48a364355a..957d690a0361 100644 --- a/learning/tour-of-beam/frontend/lib/auth/notifier.dart +++ b/learning/tour-of-beam/frontend/lib/auth/notifier.dart @@ -29,15 +29,16 @@ class AuthNotifier extends ChangeNotifier { ); AuthNotifier() { - FirebaseAuth.instance.authStateChanges().listen((user) async { + FirebaseAuth.instance.authStateChanges().listen((user) { notifyListeners(); }); } bool get isAuthenticated => FirebaseAuth.instance.currentUser != null; - Future get token async => - await FirebaseAuth.instance.currentUser?.getIdToken(); + Future getToken() async { + return FirebaseAuth.instance.currentUser?.getIdToken(); + } Future logIn(AuthMethod authMethod) async { await FirebaseAuth.instance.signInWithPopup(_authProviders.get(authMethod)); diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart index 50fc78c95dc7..ad1320762303 100644 --- a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart @@ -34,16 +34,16 @@ class UserProgressCache extends Cache { return getCompletedUnits().contains(unitId); } - void updateCompletedUnits() { + Future updateCompletedUnits() async { final sdkId = GetIt.instance.get().sdkId; if (sdkId != null) { - unawaited(_loadCompletedUnits(sdkId)); + await _loadCompletedUnits(sdkId); } } Set getCompletedUnits() { if (_future == null) { - updateCompletedUnits(); + unawaited(updateCompletedUnits()); } return _completedUnitIds; diff --git a/learning/tour-of-beam/frontend/lib/components/footer.dart b/learning/tour-of-beam/frontend/lib/components/footer.dart index e801836bb898..08af18188f04 100644 --- a/learning/tour-of-beam/frontend/lib/components/footer.dart +++ b/learning/tour-of-beam/frontend/lib/components/footer.dart @@ -16,6 +16,8 @@ * limitations under the License. */ +import 'dart:async'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; @@ -90,7 +92,7 @@ class _ReportIssueButton extends StatelessWidget { return TextButton( style: _linkButtonStyle, onPressed: () { - launchUrl(Uri.parse(BeamLinks.reportIssue)); + unawaited(launchUrl(Uri.parse(BeamLinks.reportIssue))); }, child: const Text('ui.reportIssue').tr(), ); @@ -105,7 +107,7 @@ class _PrivacyPolicyButton extends StatelessWidget { return TextButton( style: _linkButtonStyle, onPressed: () { - launchUrl(Uri.parse(BeamLinks.privacyPolicy)); + unawaited(launchUrl(Uri.parse(BeamLinks.privacyPolicy))); }, child: const Text('ui.privacyPolicy').tr(), ); diff --git a/learning/tour-of-beam/frontend/lib/components/login/button.dart b/learning/tour-of-beam/frontend/lib/components/login/button.dart index 2e56c26dcc51..42da3298783c 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/button.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/button.dart @@ -20,7 +20,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; -import '../open_overlay.dart'; import 'content.dart'; class LoginButton extends StatelessWidget { @@ -31,7 +30,7 @@ class LoginButton extends StatelessWidget { return TextButton( onPressed: () { final closeNotifier = PublicNotifier(); - kOpenOverlay( + openOverlay( context, closeNotifier, LoginContent(onLoggedIn: closeNotifier.notifyPublic), diff --git a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart index 8792d5c14744..fd72518897e4 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart @@ -20,8 +20,6 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; -import '../../generated/assets.gen.dart'; -import '../open_overlay.dart'; import 'user_menu.dart'; class Avatar extends StatelessWidget { @@ -34,7 +32,7 @@ class Avatar extends StatelessWidget { return GestureDetector( onTap: () { final closeNotifier = PublicNotifier(); - kOpenOverlay( + openOverlay( context, closeNotifier, UserMenu( @@ -45,10 +43,11 @@ class Avatar extends StatelessWidget { }, child: CircleAvatar( backgroundColor: BeamColors.white, - foregroundImage: photoUrl == null - // TODO(nausharipov): placeholder avatar asset - ? AssetImage(Assets.png.laptopLight.path) as ImageProvider - : NetworkImage(photoUrl), + foregroundImage: photoUrl == null ? null : NetworkImage(photoUrl), + child: const Icon( + Icons.person, + color: BeamColors.grey3, + ), ), ); } diff --git a/learning/tour-of-beam/frontend/lib/config.dart b/learning/tour-of-beam/frontend/lib/config.dart index 27dff083af8f..b7ed542e1b05 100644 --- a/learning/tour-of-beam/frontend/lib/config.dart +++ b/learning/tour-of-beam/frontend/lib/config.dart @@ -18,15 +18,22 @@ // TODO(alexeyinkin): Generate this file on deployment. -const _cloudFunctionsProjectRegion = 'us-east1'; -const _cloudFunctionsProjectId = 'astest-369409'; +const _cloudFunctionsProjectRegion = 'us-central1'; +const _cloudFunctionsProjectId = 'tour-of-beam-2'; const cloudFunctionsBaseUrl = 'https://' '$_cloudFunctionsProjectRegion-$_cloudFunctionsProjectId' '.cloudfunctions.net'; + // Copied from Playground's config.g.dart + const String kAnalyticsUA = 'UA-73650088-2'; -const String kApiClientURL = 'https://router.dev-playground.online/'; -const String kApiJavaClientURL = 'https://java.dev-playground.online/'; -const String kApiGoClientURL = 'https://go.dev-playground.online/'; -const String kApiPythonClientURL = 'https://python.dev-playground.online/'; -const String kApiScioClientURL = 'https://scio.dev-playground.online/'; +const String kApiClientURL = + 'https://backend-router-beta-dot-apache-beam-testing.appspot.com'; +const String kApiJavaClientURL = + 'https://backend-java-beta-dot-apache-beam-testing.appspot.com'; +const String kApiGoClientURL = + 'https://backend-go-beta-dot-apache-beam-testing.appspot.com'; +const String kApiPythonClientURL = + 'https://backend-python-beta-dot-apache-beam-testing.appspot.com'; +const String kApiScioClientURL = + 'https://backend-scio-beta-dot-apache-beam-testing.appspot.com'; diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 83718744e6fe..cc4d1e42bda1 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -16,6 +16,8 @@ * limitations under the License. */ +import 'dart:async'; + import 'package:app_state/app_state.dart'; import 'package:flutter/widgets.dart'; import 'package:get_it/get_it.dart'; @@ -35,7 +37,6 @@ import 'path.dart'; class TourNotifier extends ChangeNotifier with PageStateMixin { final ContentTreeController contentTreeController; final PlaygroundController playgroundController; - // TODO(nausharipov): avoid late? UnitController? currentUnitController; final _appNotifier = GetIt.instance.get(); final _authNotifier = GetIt.instance.get(); @@ -84,7 +85,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { } void _onUserProgressChanged() { - _userProgressCache.updateCompletedUnits(); + unawaited(_userProgressCache.updateCompletedUnits()); } void _onAppNotifierChanged() { @@ -130,22 +131,26 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { return; } - playgroundController.examplesLoader.load( - ExamplesLoadingDescriptor( - descriptors: [ - UserSharedExampleLoadingDescriptor(snippetId: taskSnippetId), - ], + unawaited( + playgroundController.examplesLoader.load( + ExamplesLoadingDescriptor( + descriptors: [ + UserSharedExampleLoadingDescriptor(snippetId: taskSnippetId), + ], + ), ), ); } // TODO(alexeyinkin): Hide the entire right pane instead. void _emptyPlayground() { - playgroundController.examplesLoader.load( - ExamplesLoadingDescriptor( - descriptors: [ - EmptyExampleLoadingDescriptor(sdk: contentTreeController.sdk), - ], + unawaited( + playgroundController.examplesLoader.load( + ExamplesLoadingDescriptor( + descriptors: [ + EmptyExampleLoadingDescriptor(sdk: contentTreeController.sdk), + ], + ), ), ); } @@ -178,11 +183,13 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { examplesLoader: ExamplesLoader(), ); - playgroundController.examplesLoader.load( - ExamplesLoadingDescriptor( - descriptors: [ - EmptyExampleLoadingDescriptor(sdk: Sdk.parseOrCreate(initialSdkId)), - ], + unawaited( + playgroundController.examplesLoader.load( + ExamplesLoadingDescriptor( + descriptors: [ + EmptyExampleLoadingDescriptor(sdk: Sdk.parseOrCreate(initialSdkId)), + ], + ), ), ); @@ -194,7 +201,6 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { _unitContentCache.removeListener(_onUnitChanged); contentTreeController.removeListener(_onUnitChanged); currentUnitController?.removeListener(_onUserProgressChanged); - _appNotifier.removeListener(_onUserProgressChanged); _appNotifier.removeListener(_onAppNotifierChanged); _authNotifier.removeListener(_onUserProgressChanged); super.dispose(); diff --git a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart index ccdaa92913ff..bd510a172d3a 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart @@ -73,7 +73,7 @@ class CloudFunctionsTobClient extends TobClient { @override Future?> getUserProgress(String sdkId) async { - final token = await GetIt.instance.get().token; + final token = await GetIt.instance.get().getToken(); if (token == null) { return null; } @@ -92,7 +92,7 @@ class CloudFunctionsTobClient extends TobClient { @override Future postUnitComplete(String sdkId, String id) async { - final token = await GetIt.instance.get().token; + final token = await GetIt.instance.get().getToken(); final json = await http.post( Uri.parse( '$cloudFunctionsBaseUrl/postUnitComplete?sdk=$sdkId&id=$id', diff --git a/playground/frontend/playground_components/lib/playground_components.dart b/playground/frontend/playground_components/lib/playground_components.dart index c245dfe6f78a..ef8fd34a6a5c 100644 --- a/playground/frontend/playground_components/lib/playground_components.dart +++ b/playground/frontend/playground_components/lib/playground_components.dart @@ -66,6 +66,7 @@ export 'src/widgets/divider.dart'; export 'src/widgets/header_icon_button.dart'; export 'src/widgets/loading_indicator.dart'; export 'src/widgets/logo.dart'; +export 'src/widgets/open_overlay.dart'; export 'src/widgets/output/output.dart'; export 'src/widgets/reset_button.dart'; export 'src/widgets/run_or_cancel_button.dart'; diff --git a/learning/tour-of-beam/frontend/lib/components/open_overlay.dart b/playground/frontend/playground_components/lib/src/widgets/open_overlay.dart similarity index 98% rename from learning/tour-of-beam/frontend/lib/components/open_overlay.dart rename to playground/frontend/playground_components/lib/src/widgets/open_overlay.dart index ed93fe881c24..30749d7b522b 100644 --- a/learning/tour-of-beam/frontend/lib/components/open_overlay.dart +++ b/playground/frontend/playground_components/lib/src/widgets/open_overlay.dart @@ -19,7 +19,7 @@ import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; -void kOpenOverlay( +void openOverlay( BuildContext context, PublicNotifier closeNotifier, Widget child, From 65dc5219943a948e7922da44ce34b54474bffaf1 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 28 Nov 2022 21:12:22 +0600 Subject: [PATCH 39/65] updating & blocking complete unit button (#23692) --- .../frontend/lib/cache/user_progress.dart | 14 +++++++ .../frontend/lib/enums/unit_completion.dart | 28 ++++++++++++++ learning/tour-of-beam/frontend/lib/main.dart | 6 ++- .../frontend/lib/models/user_progress.dart | 1 + .../lib/pages/tour/controllers/unit.dart | 4 ++ .../frontend/lib/pages/tour/state.dart | 20 +++++++--- .../tour/widgets/complete_unit_button.dart | 37 ++++++++++++++----- 7 files changed, 95 insertions(+), 15 deletions(-) create mode 100644 learning/tour-of-beam/frontend/lib/enums/unit_completion.dart diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart index ad1320762303..69620215979f 100644 --- a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart @@ -28,8 +28,22 @@ class UserProgressCache extends Cache { UserProgressCache({required super.client}); final _completedUnitIds = {}; + final _updatingUnitIds = {}; Future?>? _future; + Set getUpdatingUnitIds() => _updatingUnitIds; + + void addUpdatingUnitId(String unitId) { + _updatingUnitIds.add(unitId); + notifyListeners(); + } + + void removeUpdatingUnitId(String unitId) { + _updatingUnitIds.remove(unitId); + + /// No need to nofity, because UnitController does. + } + bool isUnitCompleted(String? unitId) { return getCompletedUnits().contains(unitId); } diff --git a/learning/tour-of-beam/frontend/lib/enums/unit_completion.dart b/learning/tour-of-beam/frontend/lib/enums/unit_completion.dart new file mode 100644 index 000000000000..e77371425fd4 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/enums/unit_completion.dart @@ -0,0 +1,28 @@ +/* + * 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. + */ + +enum UnitCompletion { + completed, + uncompleted, + + /// Sent the request to complete or to undo completion. + updating, + + /// User is not authenticated + blocked, +} diff --git a/learning/tour-of-beam/frontend/lib/main.dart b/learning/tour-of-beam/frontend/lib/main.dart index 7a51f84de79c..1fcf3b273bba 100644 --- a/learning/tour-of-beam/frontend/lib/main.dart +++ b/learning/tour-of-beam/frontend/lib/main.dart @@ -31,7 +31,11 @@ import 'firebase_options.dart'; import 'locator.dart'; import 'router/route_information_parser.dart'; -// TODO(nausharipov): reproduce "ScrollController not attached to any scroll views." +// TODO(nausharipov): fix "ScrollController not attached to any scroll views." +// Steps to reproduce: +// 1. Open a unit with horizontally scrollable code blocks. +// 2. Scroll a block. +// 3. See the error. void main() async { await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, diff --git a/learning/tour-of-beam/frontend/lib/models/user_progress.dart b/learning/tour-of-beam/frontend/lib/models/user_progress.dart index b2d40823c920..d65cb849f4f5 100644 --- a/learning/tour-of-beam/frontend/lib/models/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/models/user_progress.dart @@ -22,6 +22,7 @@ part 'user_progress.g.dart'; @JsonSerializable(createToJson: false) class UserProgressModel { + @JsonKey(name: 'id') final String unitId; final bool isCompleted; diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart index 45bde4993d20..9ed5726fa530 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart @@ -19,6 +19,7 @@ import 'package:flutter/widgets.dart'; import 'package:get_it/get_it.dart'; +import '../../../cache/user_progress.dart'; import '../../../repositories/client/client.dart'; class UnitController extends ChangeNotifier { @@ -32,7 +33,10 @@ class UnitController extends ChangeNotifier { Future completeUnit() async { final client = GetIt.instance.get(); + final userProgressCache = GetIt.instance.get(); + userProgressCache.addUpdatingUnitId(unitId); await client.postUnitComplete(sdkId, unitId); + userProgressCache.removeUpdatingUnitId(unitId); notifyListeners(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index cc4d1e42bda1..83d444352b52 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -27,6 +27,7 @@ import '../../auth/notifier.dart'; import '../../cache/unit_content.dart'; import '../../cache/user_progress.dart'; import '../../config.dart'; +import '../../enums/unit_completion.dart'; import '../../models/unit.dart'; import '../../models/unit_content.dart'; import '../../state.dart'; @@ -68,11 +69,20 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { ); bool canCompleteCurrentUnit() { - return _authNotifier.isAuthenticated && - // TODO(nausharipov): is completing - // !currentUnitController.isCompleting && - !_userProgressCache - .isUnitCompleted(contentTreeController.currentNode?.id); + return getCurrentUnitCompletion() == UnitCompletion.uncompleted; + } + + UnitCompletion getCurrentUnitCompletion() { + final unitId = currentUnitController?.unitId; + if (!_authNotifier.isAuthenticated) { + return UnitCompletion.blocked; + } else if (_userProgressCache.getUpdatingUnitIds().contains(unitId)) { + return UnitCompletion.updating; + } else if (_userProgressCache.isUnitCompleted(unitId)) { + return UnitCompletion.completed; + } else { + return UnitCompletion.uncompleted; + } } UnitContentModel? get currentUnitContent => _currentUnitContent; diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart index a570b3d6649b..1d9f501de00a 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart @@ -1,3 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; @@ -18,27 +36,28 @@ class CompleteUnitButton extends StatelessWidget { return AnimatedBuilder( animation: userProgressCache, builder: (context, child) { + final canComplete = tourNotifier.canCompleteCurrentUnit(); + final borderColor = + canComplete ? themeData.primaryColor : themeData.disabledColor; + final onPressed = canComplete + ? tourNotifier.currentUnitController?.completeUnit + : null; + return Flexible( child: OutlinedButton( style: OutlinedButton.styleFrom( foregroundColor: themeData.primaryColor, - side: BorderSide( - color: tourNotifier.canCompleteCurrentUnit() - ? themeData.primaryColor - : themeData.disabledColor, - ), + side: BorderSide(color: borderColor), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all( Radius.circular(BeamSizes.size4), ), ), ), - onPressed: tourNotifier.canCompleteCurrentUnit() - ? tourNotifier.currentUnitController?.completeUnit - : null, + onPressed: onPressed, child: const Text( 'pages.tour.completeUnit', - overflow: TextOverflow.ellipsis, + overflow: TextOverflow.visible, ).tr(), ), ); From d55622e30df308eb61a42ecd1f03930012ec0cb8 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 28 Nov 2022 21:15:15 +0600 Subject: [PATCH 40/65] missing await --- learning/tour-of-beam/frontend/lib/auth/notifier.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/learning/tour-of-beam/frontend/lib/auth/notifier.dart b/learning/tour-of-beam/frontend/lib/auth/notifier.dart index 957d690a0361..c6b147ad02d0 100644 --- a/learning/tour-of-beam/frontend/lib/auth/notifier.dart +++ b/learning/tour-of-beam/frontend/lib/auth/notifier.dart @@ -37,7 +37,7 @@ class AuthNotifier extends ChangeNotifier { bool get isAuthenticated => FirebaseAuth.instance.currentUser != null; Future getToken() async { - return FirebaseAuth.instance.currentUser?.getIdToken(); + return await FirebaseAuth.instance.currentUser?.getIdToken(); } Future logIn(AuthMethod authMethod) async { From c6004b0f220be0959b1fadc1fcffb04e4004cd97 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Mon, 28 Nov 2022 21:17:16 +0600 Subject: [PATCH 41/65] no final else --- learning/tour-of-beam/frontend/lib/pages/tour/state.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 83d444352b52..10e2029b5fd8 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -80,9 +80,8 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { return UnitCompletion.updating; } else if (_userProgressCache.isUnitCompleted(unitId)) { return UnitCompletion.completed; - } else { - return UnitCompletion.uncompleted; } + return UnitCompletion.uncompleted; } UnitContentModel? get currentUnitContent => _currentUnitContent; From 0a76b4019647ebcbec76739b078b01fddd37789b Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 29 Nov 2022 11:03:17 +0600 Subject: [PATCH 42/65] pubspec.lock ignored only in PGC --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5a9e81a34dc3..14ee8c403313 100644 --- a/.gitignore +++ b/.gitignore @@ -127,7 +127,7 @@ website/www/yarn-error.log **/*.g.dart **/*.mocks.dart **/.packages -**/pubspec.lock +**/playground_components/pubspec.lock # Ignore Beam Playground Terraform **/.terraform From 749d8b19bea072be84cace76bd1fb998a3a76531 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 29 Nov 2022 11:03:34 +0600 Subject: [PATCH 43/65] pubspec.lock --- learning/tour-of-beam/frontend/pubspec.lock | 1124 +++++++++++++++++++ 1 file changed, 1124 insertions(+) create mode 100644 learning/tour-of-beam/frontend/pubspec.lock diff --git a/learning/tour-of-beam/frontend/pubspec.lock b/learning/tour-of-beam/frontend/pubspec.lock new file mode 100644 index 000000000000..1512e778a3d3 --- /dev/null +++ b/learning/tour-of-beam/frontend/pubspec.lock @@ -0,0 +1,1124 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "46.0.0" + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.9" + aligned_dialog: + dependency: transitive + description: + name: aligned_dialog + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.6" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "4.6.0" + app_state: + dependency: "direct main" + description: + name: app_state + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.1" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.0" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.9.0" + autotrie: + dependency: transitive + description: + name: autotrie + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.9" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.2.3" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.4.1" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + cloud_firestore_platform_interface: + dependency: transitive + description: + name: cloud_firestore_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "5.9.0" + cloud_firestore_web: + dependency: transitive + description: + name: cloud_firestore_web + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.0" + collection: + dependency: "direct main" + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.16.0" + color: + dependency: transitive + description: + name: color + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" + csv: + dependency: transitive + description: + name: csv + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.1" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.3" + dartx: + dependency: transitive + description: + name: dartx + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + easy_localization: + dependency: "direct main" + description: + name: easy_localization + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + easy_localization_ext: + dependency: "direct main" + description: + name: easy_localization_ext + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.1" + easy_localization_loader: + dependency: "direct main" + description: + name: easy_localization_loader + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + easy_logger: + dependency: transitive + description: + name: easy_logger + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.2" + enum_map: + dependency: "direct main" + description: + name: enum_map + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" + enum_map_gen: + dependency: "direct dev" + description: + name: enum_map_gen + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" + equatable: + dependency: "direct dev" + description: + name: equatable + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.2" + firebase_auth: + dependency: "direct main" + description: + name: firebase_auth + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.4" + firebase_auth_platform_interface: + dependency: transitive + description: + name: firebase_auth_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "6.11.3" + firebase_auth_web: + dependency: transitive + description: + name: firebase_auth_web + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.3" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "4.5.2" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_code_editor: + dependency: transitive + description: + name: flutter_code_editor + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.11" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_gen_core: + dependency: transitive + description: + name: flutter_gen_core + url: "https://pub.dartlang.org" + source: hosted + version: "4.3.0" + flutter_gen_runner: + dependency: "direct dev" + description: + name: flutter_gen_runner + url: "https://pub.dartlang.org" + source: hosted + version: "4.3.0" + flutter_highlight: + dependency: transitive + description: + name: flutter_highlight + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.0" + flutter_issue_108697_workaround: + dependency: transitive + description: + name: flutter_issue_108697_workaround + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2" + flutter_localizations: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_markdown: + dependency: "direct main" + description: + name: flutter_markdown + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.12" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + get_it: + dependency: "direct main" + description: + name: get_it + url: "https://pub.dartlang.org" + source: hosted + version: "7.2.0" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + google_sign_in: + dependency: "direct main" + description: + name: google_sign_in + url: "https://pub.dartlang.org" + source: hosted + version: "5.4.2" + google_sign_in_android: + dependency: transitive + description: + name: google_sign_in_android + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.4" + google_sign_in_ios: + dependency: transitive + description: + name: google_sign_in_ios + url: "https://pub.dartlang.org" + source: hosted + version: "5.5.1" + google_sign_in_platform_interface: + dependency: transitive + description: + name: google_sign_in_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + google_sign_in_web: + dependency: transitive + description: + name: google_sign_in_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.2" + googleapis_auth: + dependency: transitive + description: + name: googleapis_auth + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + grpc: + dependency: transitive + description: + name: grpc + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" + highlight: + dependency: transitive + description: + name: highlight + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.0" + hive: + dependency: transitive + description: + name: hive + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.3" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.5" + http2: + dependency: transitive + description: + name: http2 + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.1" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.4" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.7.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + url: "https://pub.dartlang.org" + source: hosted + version: "6.4.1" + linked_scroll_controller: + dependency: transitive + description: + name: linked_scroll_controller + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + markdown: + dependency: "direct main" + description: + name: markdown + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.12" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.5" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + nested: + dependency: transitive + description: + name: nested + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.2" + path_drawing: + dependency: transitive + description: + name: path_drawing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + path_provider: + dependency: transitive + description: + name: path_provider + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.17" + path_provider_ios: + dependency: transitive + description: + name: path_provider_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.7" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.6" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.0" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + playground_components: + dependency: "direct main" + description: + path: "../../../playground/frontend/playground_components" + relative: true + source: path + version: "0.0.1" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.1" + process: + dependency: transitive + description: + name: process + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.4" + protobuf: + dependency: transitive + description: + name: protobuf + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + provider: + dependency: "direct main" + description: + name: provider + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.3" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + rxdart: + dependency: transitive + description: + name: rxdart + url: "https://pub.dartlang.org" + source: hosted + version: "0.27.5" + scrollable_positioned_list: + dependency: transitive + description: + name: scrollable_positioned_list + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.15" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.12" + shared_preferences_ios: + dependency: transitive + description: + name: shared_preferences_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.5" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.3" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.9.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + sync_http: + dependency: transitive + description: + name: sync_http + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.12" + time: + dependency: transitive + description: + name: time + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + total_lints: + dependency: "direct dev" + description: + name: total_lints + url: "https://pub.dartlang.org" + source: hosted + version: "2.17.4" + tuple: + dependency: transitive + description: + name: tuple + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.5" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.17" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.17" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.12" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + url_strategy: + dependency: "direct main" + description: + name: url_strategy + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + vm_service: + dependency: transitive + description: + name: vm_service + url: "https://pub.dartlang.org" + source: hosted + version: "9.0.0" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + webdriver: + dependency: transitive + description: + name: webdriver + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + win32: + dependency: transitive + description: + name: win32 + url: "https://pub.dartlang.org" + source: hosted + version: "2.7.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0+1" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "5.4.1" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" +sdks: + dart: ">=2.18.1 <3.0.0" + flutter: ">=3.3.2" From fb1fea1af8069ae02ba261781ca923cd40796c97 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 29 Nov 2022 11:43:06 +0600 Subject: [PATCH 44/65] comment fixes (4) --- .../frontend/lib/cache/user_progress.dart | 23 +++++++++++++++++++ .../frontend/lib/enums/unit_completion.dart | 4 +--- .../lib/pages/tour/controllers/unit.dart | 9 +++++--- .../frontend/lib/pages/tour/state.dart | 20 +--------------- .../tour/widgets/complete_unit_button.dart | 3 ++- 5 files changed, 33 insertions(+), 26 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart index 69620215979f..9f24573f01d4 100644 --- a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart @@ -20,6 +20,8 @@ import 'dart:async'; import 'package:get_it/get_it.dart'; +import '../auth/notifier.dart'; +import '../enums/unit_completion.dart'; import '../models/user_progress.dart'; import '../state.dart'; import 'cache.dart'; @@ -44,6 +46,27 @@ class UserProgressCache extends Cache { /// No need to nofity, because UnitController does. } + bool canCompleteUnit(String? unitId) { + if (unitId == null) { + return false; + } + return _getUnitCompletion(unitId) == UnitCompletion.uncompleted; + } + + UnitCompletion _getUnitCompletion(String unitId) { + final authNotifier = GetIt.instance.get(); + if (!authNotifier.isAuthenticated) { + return UnitCompletion.unauthenticated; + } + if (_updatingUnitIds.contains(unitId)) { + return UnitCompletion.updating; + } + if (isUnitCompleted(unitId)) { + return UnitCompletion.completed; + } + return UnitCompletion.uncompleted; + } + bool isUnitCompleted(String? unitId) { return getCompletedUnits().contains(unitId); } diff --git a/learning/tour-of-beam/frontend/lib/enums/unit_completion.dart b/learning/tour-of-beam/frontend/lib/enums/unit_completion.dart index e77371425fd4..746cfd4d38e5 100644 --- a/learning/tour-of-beam/frontend/lib/enums/unit_completion.dart +++ b/learning/tour-of-beam/frontend/lib/enums/unit_completion.dart @@ -22,7 +22,5 @@ enum UnitCompletion { /// Sent the request to complete or to undo completion. updating, - - /// User is not authenticated - blocked, + unauthenticated, } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart index 9ed5726fa530..97286f04de6d 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart @@ -34,9 +34,12 @@ class UnitController extends ChangeNotifier { Future completeUnit() async { final client = GetIt.instance.get(); final userProgressCache = GetIt.instance.get(); - userProgressCache.addUpdatingUnitId(unitId); - await client.postUnitComplete(sdkId, unitId); - userProgressCache.removeUpdatingUnitId(unitId); + try { + userProgressCache.addUpdatingUnitId(unitId); + await client.postUnitComplete(sdkId, unitId); + } finally { + userProgressCache.removeUpdatingUnitId(unitId); + } notifyListeners(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 10e2029b5fd8..26d1e5f2076f 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -27,7 +27,6 @@ import '../../auth/notifier.dart'; import '../../cache/unit_content.dart'; import '../../cache/user_progress.dart'; import '../../config.dart'; -import '../../enums/unit_completion.dart'; import '../../models/unit.dart'; import '../../models/unit_content.dart'; import '../../state.dart'; @@ -60,30 +59,13 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { _onUnitChanged(); } - // TODO(nausharipov): currentUnitId getter? - @override PagePath get path => TourPath( sdkId: contentTreeController.sdkId, treeIds: contentTreeController.treeIds, ); - bool canCompleteCurrentUnit() { - return getCurrentUnitCompletion() == UnitCompletion.uncompleted; - } - - UnitCompletion getCurrentUnitCompletion() { - final unitId = currentUnitController?.unitId; - if (!_authNotifier.isAuthenticated) { - return UnitCompletion.blocked; - } else if (_userProgressCache.getUpdatingUnitIds().contains(unitId)) { - return UnitCompletion.updating; - } else if (_userProgressCache.isUnitCompleted(unitId)) { - return UnitCompletion.completed; - } - return UnitCompletion.uncompleted; - } - + String? get currentUnitId => currentUnitController?.unitId; UnitContentModel? get currentUnitContent => _currentUnitContent; void _createCurrentUnitController(String sdkId, String unitId) { diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart index 1d9f501de00a..f9c1090f7494 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart @@ -36,7 +36,8 @@ class CompleteUnitButton extends StatelessWidget { return AnimatedBuilder( animation: userProgressCache, builder: (context, child) { - final canComplete = tourNotifier.canCompleteCurrentUnit(); + final canComplete = + userProgressCache.canCompleteUnit(tourNotifier.currentUnitId); final borderColor = canComplete ? themeData.primaryColor : themeData.disabledColor; final onPressed = canComplete From ef637403aa114f43f82ac005254632f2d35e0bad Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 29 Nov 2022 13:09:58 +0600 Subject: [PATCH 45/65] rearranged completeUnit (#23692) --- learning/tour-of-beam/frontend/lib/cache/user_progress.dart | 3 +-- .../tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart | 2 +- learning/tour-of-beam/frontend/lib/pages/tour/state.dart | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart index 9f24573f01d4..6431cd2fd6ff 100644 --- a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart @@ -42,8 +42,7 @@ class UserProgressCache extends Cache { void removeUpdatingUnitId(String unitId) { _updatingUnitIds.remove(unitId); - - /// No need to nofity, because UnitController does. + notifyListeners(); } bool canCompleteUnit(String? unitId) { diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart index 97286f04de6d..c7f3ee239efa 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart @@ -38,8 +38,8 @@ class UnitController extends ChangeNotifier { userProgressCache.addUpdatingUnitId(unitId); await client.postUnitComplete(sdkId, unitId); } finally { + await userProgressCache.updateCompletedUnits(); userProgressCache.removeUpdatingUnitId(unitId); } - notifyListeners(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 26d1e5f2076f..d68491ec4f2c 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -72,7 +72,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { currentUnitController = UnitController( unitId: unitId, sdkId: sdkId, - )..addListener(_onUserProgressChanged); + ); } void _onUserProgressChanged() { @@ -191,7 +191,6 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { void dispose() { _unitContentCache.removeListener(_onUnitChanged); contentTreeController.removeListener(_onUnitChanged); - currentUnitController?.removeListener(_onUserProgressChanged); _appNotifier.removeListener(_onAppNotifierChanged); _authNotifier.removeListener(_onUserProgressChanged); super.dispose(); From 4b2d855920d6d63dfff4412fc9bdfb9ddbbdd695 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 29 Nov 2022 13:30:12 +0600 Subject: [PATCH 46/65] renamed user progress model to unit progress (#23692) --- .../frontend/lib/cache/user_progress.dart | 8 ++++---- .../{user_progress.dart => unit_progress.dart} | 15 +++++++-------- .../frontend/lib/repositories/client/client.dart | 4 ++-- .../client/cloud_functions_client.dart | 5 ++--- .../models/get_user_progress_response.dart | 4 ++-- 5 files changed, 17 insertions(+), 19 deletions(-) rename learning/tour-of-beam/frontend/lib/models/{user_progress.dart => unit_progress.dart} (78%) diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart index 6431cd2fd6ff..1dcd41b7856d 100644 --- a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart @@ -22,7 +22,7 @@ import 'package:get_it/get_it.dart'; import '../auth/notifier.dart'; import '../enums/unit_completion.dart'; -import '../models/user_progress.dart'; +import '../repositories/models/get_user_progress_response.dart'; import '../state.dart'; import 'cache.dart'; @@ -31,7 +31,7 @@ class UserProgressCache extends Cache { final _completedUnitIds = {}; final _updatingUnitIds = {}; - Future?>? _future; + Future? _future; Set getUpdatingUnitIds() => _updatingUnitIds; @@ -91,9 +91,9 @@ class UserProgressCache extends Cache { _completedUnitIds.clear(); if (result != null) { - for (final unitProgress in result) { + for (final unitProgress in result.units) { if (unitProgress.isCompleted) { - _completedUnitIds.add(unitProgress.unitId); + _completedUnitIds.add(unitProgress.id); } } } diff --git a/learning/tour-of-beam/frontend/lib/models/user_progress.dart b/learning/tour-of-beam/frontend/lib/models/unit_progress.dart similarity index 78% rename from learning/tour-of-beam/frontend/lib/models/user_progress.dart rename to learning/tour-of-beam/frontend/lib/models/unit_progress.dart index d65cb849f4f5..473c8ae0d4e6 100644 --- a/learning/tour-of-beam/frontend/lib/models/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/models/unit_progress.dart @@ -18,19 +18,18 @@ import 'package:json_annotation/json_annotation.dart'; -part 'user_progress.g.dart'; +part 'unit_progress.g.dart'; @JsonSerializable(createToJson: false) -class UserProgressModel { - @JsonKey(name: 'id') - final String unitId; +class UnitProgressModel { + final String id; final bool isCompleted; - const UserProgressModel({ - required this.unitId, + const UnitProgressModel({ + required this.id, required this.isCompleted, }); - factory UserProgressModel.fromJson(Map json) => - _$UserProgressModelFromJson(json); + factory UnitProgressModel.fromJson(Map json) => + _$UnitProgressModelFromJson(json); } diff --git a/learning/tour-of-beam/frontend/lib/repositories/client/client.dart b/learning/tour-of-beam/frontend/lib/repositories/client/client.dart index 45980af1a81c..66fd4a996316 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/client/client.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/client/client.dart @@ -18,8 +18,8 @@ import '../../models/content_tree.dart'; import '../../models/unit_content.dart'; -import '../../models/user_progress.dart'; import '../models/get_sdks_response.dart'; +import '../models/get_user_progress_response.dart'; abstract class TobClient { Future getContentTree(String sdkId); @@ -28,7 +28,7 @@ abstract class TobClient { Future getUnitContent(String sdkId, String unitId); - Future?> getUserProgress(String sdkId); + Future getUserProgress(String sdkId); Future postUnitComplete(String sdkId, String id); } diff --git a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart index bd510a172d3a..4295115c8a4d 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart @@ -26,7 +26,6 @@ import '../../auth/notifier.dart'; import '../../config.dart'; import '../../models/content_tree.dart'; import '../../models/unit_content.dart'; -import '../../models/user_progress.dart'; import '../models/get_content_tree_response.dart'; import '../models/get_sdks_response.dart'; import '../models/get_user_progress_response.dart'; @@ -72,7 +71,7 @@ class CloudFunctionsTobClient extends TobClient { } @override - Future?> getUserProgress(String sdkId) async { + Future getUserProgress(String sdkId) async { final token = await GetIt.instance.get().getToken(); if (token == null) { return null; @@ -87,7 +86,7 @@ class CloudFunctionsTobClient extends TobClient { ); final map = jsonDecode(utf8.decode(json.bodyBytes)) as Map; final response = GetUserProgressResponse.fromJson(map); - return response.units; + return response; } @override diff --git a/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart b/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart index 8328c99fb9d4..b9ef766c99dd 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart @@ -18,13 +18,13 @@ import 'package:json_annotation/json_annotation.dart'; -import '../../models/user_progress.dart'; +import '../../models/unit_progress.dart'; part 'get_user_progress_response.g.dart'; @JsonSerializable(createToJson: false) class GetUserProgressResponse { - final List units; + final List units; const GetUserProgressResponse({required this.units}); From 27b26e41a81f07faac060c3d2e45f5b7bea19d5a Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 29 Nov 2022 13:31:24 +0600 Subject: [PATCH 47/65] clearUpdatingUnitId (#23692) --- learning/tour-of-beam/frontend/lib/cache/user_progress.dart | 2 +- .../tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart index 1dcd41b7856d..3bff661ceb23 100644 --- a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/cache/user_progress.dart @@ -40,7 +40,7 @@ class UserProgressCache extends Cache { notifyListeners(); } - void removeUpdatingUnitId(String unitId) { + void clearUpdatingUnitId(String unitId) { _updatingUnitIds.remove(unitId); notifyListeners(); } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart index c7f3ee239efa..d65e57c3fadd 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart @@ -39,7 +39,7 @@ class UnitController extends ChangeNotifier { await client.postUnitComplete(sdkId, unitId); } finally { await userProgressCache.updateCompletedUnits(); - userProgressCache.removeUpdatingUnitId(unitId); + userProgressCache.clearUpdatingUnitId(unitId); } } } From b6c4e3e66c30fa4cbdfbbefd1a41e649c32b9ecb Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 29 Nov 2022 13:52:29 +0600 Subject: [PATCH 48/65] added async (#23692) --- .../frontend/lib/pages/tour/state.dart | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index d68491ec4f2c..53720eb33ec4 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -75,8 +75,8 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { ); } - void _onUserProgressChanged() { - unawaited(_userProgressCache.updateCompletedUnits()); + Future _onUserProgressChanged() async { + await _userProgressCache.updateCompletedUnits(); } void _onAppNotifierChanged() { @@ -105,7 +105,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { notifyListeners(); } - void _setCurrentUnitContent(UnitContentModel? content) { + Future _setCurrentUnitContent(UnitContentModel? content) async { if (content == _currentUnitContent) { return; } @@ -118,30 +118,26 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { final taskSnippetId = content.taskSnippetId; if (taskSnippetId == null) { - _emptyPlayground(); + await _emptyPlayground(); return; } - unawaited( - playgroundController.examplesLoader.load( - ExamplesLoadingDescriptor( - descriptors: [ - UserSharedExampleLoadingDescriptor(snippetId: taskSnippetId), - ], - ), + await playgroundController.examplesLoader.load( + ExamplesLoadingDescriptor( + descriptors: [ + UserSharedExampleLoadingDescriptor(snippetId: taskSnippetId), + ], ), ); } // TODO(alexeyinkin): Hide the entire right pane instead. - void _emptyPlayground() { - unawaited( - playgroundController.examplesLoader.load( - ExamplesLoadingDescriptor( - descriptors: [ - EmptyExampleLoadingDescriptor(sdk: contentTreeController.sdk), - ], - ), + Future _emptyPlayground() async { + await playgroundController.examplesLoader.load( + ExamplesLoadingDescriptor( + descriptors: [ + EmptyExampleLoadingDescriptor(sdk: contentTreeController.sdk), + ], ), ); } From 1e38328e564f72b4e18439c60610902423223dbd Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 29 Nov 2022 15:40:15 +0600 Subject: [PATCH 49/65] removed "fix exception" todo after filing an issue (#23692) --- learning/tour-of-beam/frontend/lib/main.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/main.dart b/learning/tour-of-beam/frontend/lib/main.dart index 1fcf3b273bba..7139c0b42f92 100644 --- a/learning/tour-of-beam/frontend/lib/main.dart +++ b/learning/tour-of-beam/frontend/lib/main.dart @@ -31,11 +31,6 @@ import 'firebase_options.dart'; import 'locator.dart'; import 'router/route_information_parser.dart'; -// TODO(nausharipov): fix "ScrollController not attached to any scroll views." -// Steps to reproduce: -// 1. Open a unit with horizontally scrollable code blocks. -// 2. Scroll a block. -// 3. See the error. void main() async { await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, From e215ec4c676e88d85fad3ba08e222ac19d8953b8 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Wed, 30 Nov 2022 10:37:05 +0600 Subject: [PATCH 50/65] generated files --- .../frontend/lib/auth/method.g.dart | 162 ++++++++++++++++++ .../frontend/lib/models/unit_progress.g.dart | 13 ++ .../models/get_user_progress_response.g.dart | 15 ++ .../lib/repositories/models/module.g.dart | 1 - 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 learning/tour-of-beam/frontend/lib/auth/method.g.dart create mode 100644 learning/tour-of-beam/frontend/lib/models/unit_progress.g.dart create mode 100644 learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.g.dart diff --git a/learning/tour-of-beam/frontend/lib/auth/method.g.dart b/learning/tour-of-beam/frontend/lib/auth/method.g.dart new file mode 100644 index 000000000000..e9f7c3dfb64b --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/auth/method.g.dart @@ -0,0 +1,162 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'method.dart'; + +// ************************************************************************** +// UnmodifiableEnumMapGenerator +// ************************************************************************** + +class UnmodifiableAuthMethodMap extends UnmodifiableEnumMap { + final V google; + final V github; + + const UnmodifiableAuthMethodMap({ + required this.google, + required this.github, + }); + + @override + Map cast() { + return Map.castFrom(this); + } + + @override + bool containsValue(Object? value) { + if (this.google == value) return true; + if (this.github == value) return true; + return false; + } + + @override + bool containsKey(Object? key) { + return key.runtimeType == AuthMethod; + } + + @override + V? operator [](Object? key) { + switch (key) { + case AuthMethod.google: + return this.google; + case AuthMethod.github: + return this.github; + } + + return null; + } + + @override + void operator []=(AuthMethod key, V value) { + throw Exception("Cannot modify this map."); + } + + @override + Iterable> get entries { + return [ + MapEntry(AuthMethod.google, this.google), + MapEntry(AuthMethod.github, this.github), + ]; + } + + @override + Map map(MapEntry transform(AuthMethod key, V value)) { + final google = transform(AuthMethod.google, this.google); + final github = transform(AuthMethod.github, this.github); + return { + google.key: google.value, + github.key: github.value, + }; + } + + @override + void addEntries(Iterable> newEntries) { + throw Exception("Cannot modify this map."); + } + + @override + V update(AuthMethod key, V update(V value), {V Function()? ifAbsent}) { + throw Exception("Cannot modify this map."); + } + + @override + void updateAll(V update(AuthMethod key, V value)) { + throw Exception("Cannot modify this map."); + } + + @override + void removeWhere(bool test(AuthMethod key, V value)) { + throw Exception("Objects in this map cannot be removed."); + } + + @override + V putIfAbsent(AuthMethod key, V ifAbsent()) { + return this.get(key); + } + + @override + void addAll(Map other) { + throw Exception("Cannot modify this map."); + } + + @override + V? remove(Object? key) { + throw Exception("Objects in this map cannot be removed."); + } + + @override + void clear() { + throw Exception("Objects in this map cannot be removed."); + } + + @override + void forEach(void action(AuthMethod key, V value)) { + action(AuthMethod.google, this.google); + action(AuthMethod.github, this.github); + } + + @override + Iterable get keys { + return AuthMethod.values; + } + + @override + Iterable get values { + return [ + this.google, + this.github, + ]; + } + + @override + int get length { + return 2; + } + + @override + bool get isEmpty { + return false; + } + + @override + bool get isNotEmpty { + return true; + } + + V get(AuthMethod key) { + switch (key) { + case AuthMethod.google: + return this.google; + case AuthMethod.github: + return this.github; + } + } + + @override + String toString() { + final buffer = StringBuffer("{"); + buffer.write("AuthMethod.google: ${this.google}"); + buffer.write(", "); + buffer.write("AuthMethod.github: ${this.github}"); + buffer.write("}"); + return buffer.toString(); + } +} diff --git a/learning/tour-of-beam/frontend/lib/models/unit_progress.g.dart b/learning/tour-of-beam/frontend/lib/models/unit_progress.g.dart new file mode 100644 index 000000000000..c1a773cd66a9 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/models/unit_progress.g.dart @@ -0,0 +1,13 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'unit_progress.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +UnitProgressModel _$UnitProgressModelFromJson(Map json) => + UnitProgressModel( + id: json['id'] as String, + isCompleted: json['isCompleted'] as bool, + ); diff --git a/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.g.dart b/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.g.dart new file mode 100644 index 000000000000..3f4bfae2e294 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.g.dart @@ -0,0 +1,15 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'get_user_progress_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +GetUserProgressResponse _$GetUserProgressResponseFromJson( + Map json) => + GetUserProgressResponse( + units: (json['units'] as List) + .map((e) => UnitProgressModel.fromJson(e as Map)) + .toList(), + ); diff --git a/learning/tour-of-beam/frontend/lib/repositories/models/module.g.dart b/learning/tour-of-beam/frontend/lib/repositories/models/module.g.dart index 05c3e51f804a..93cda74866df 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/models/module.g.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/models/module.g.dart @@ -17,7 +17,6 @@ ModuleResponseModel _$ModuleResponseModelFromJson(Map json) => ); const _$ComplexityEnumMap = { - Complexity.unspecified: 'UNSPECIFIED', Complexity.basic: 'BASIC', Complexity.medium: 'MEDIUM', Complexity.advanced: 'ADVANCED', From a10795205507a66b8cd90ed8caaf112663a60c8c Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 1 Dec 2022 12:47:19 +0600 Subject: [PATCH 51/65] renamed user progress cache to unit progress (#23692) --- .../{user_progress.dart => unit_progress.dart} | 4 ++-- learning/tour-of-beam/frontend/lib/locator.dart | 4 ++-- .../frontend/lib/pages/tour/controllers/unit.dart | 10 +++++----- .../frontend/lib/pages/tour/state.dart | 14 +++++++------- .../pages/tour/widgets/complete_unit_button.dart | 8 ++++---- .../lib/pages/tour/widgets/group_title.dart | 8 ++++---- .../frontend/lib/pages/tour/widgets/unit.dart | 8 ++++---- 7 files changed, 28 insertions(+), 28 deletions(-) rename learning/tour-of-beam/frontend/lib/cache/{user_progress.dart => unit_progress.dart} (97%) diff --git a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart b/learning/tour-of-beam/frontend/lib/cache/unit_progress.dart similarity index 97% rename from learning/tour-of-beam/frontend/lib/cache/user_progress.dart rename to learning/tour-of-beam/frontend/lib/cache/unit_progress.dart index 3bff661ceb23..5649e7464674 100644 --- a/learning/tour-of-beam/frontend/lib/cache/user_progress.dart +++ b/learning/tour-of-beam/frontend/lib/cache/unit_progress.dart @@ -26,8 +26,8 @@ import '../repositories/models/get_user_progress_response.dart'; import '../state.dart'; import 'cache.dart'; -class UserProgressCache extends Cache { - UserProgressCache({required super.client}); +class UnitProgressCache extends Cache { + UnitProgressCache({required super.client}); final _completedUnitIds = {}; final _updatingUnitIds = {}; diff --git a/learning/tour-of-beam/frontend/lib/locator.dart b/learning/tour-of-beam/frontend/lib/locator.dart index 9d580321fc1d..7bdb0406edd0 100644 --- a/learning/tour-of-beam/frontend/lib/locator.dart +++ b/learning/tour-of-beam/frontend/lib/locator.dart @@ -23,7 +23,7 @@ import 'auth/notifier.dart'; import 'cache/content_tree.dart'; import 'cache/sdk.dart'; import 'cache/unit_content.dart'; -import 'cache/user_progress.dart'; +import 'cache/unit_progress.dart'; import 'pages/welcome/page.dart'; import 'repositories/client/client.dart'; import 'repositories/client/cloud_functions_client.dart'; @@ -48,7 +48,7 @@ void _initializeCaches() { GetIt.instance.registerSingleton(ContentTreeCache(client: client)); GetIt.instance.registerSingleton(SdkCache(client: client)); GetIt.instance.registerSingleton(UnitContentCache(client: client)); - GetIt.instance.registerSingleton(UserProgressCache(client: client)); + GetIt.instance.registerSingleton(UnitProgressCache(client: client)); } void _initializeState() { diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart index d65e57c3fadd..5331e454ff45 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart @@ -19,7 +19,7 @@ import 'package:flutter/widgets.dart'; import 'package:get_it/get_it.dart'; -import '../../../cache/user_progress.dart'; +import '../../../cache/unit_progress.dart'; import '../../../repositories/client/client.dart'; class UnitController extends ChangeNotifier { @@ -33,13 +33,13 @@ class UnitController extends ChangeNotifier { Future completeUnit() async { final client = GetIt.instance.get(); - final userProgressCache = GetIt.instance.get(); + final unitProgressCache = GetIt.instance.get(); try { - userProgressCache.addUpdatingUnitId(unitId); + unitProgressCache.addUpdatingUnitId(unitId); await client.postUnitComplete(sdkId, unitId); } finally { - await userProgressCache.updateCompletedUnits(); - userProgressCache.clearUpdatingUnitId(unitId); + await unitProgressCache.updateCompletedUnits(); + unitProgressCache.clearUpdatingUnitId(unitId); } } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 53720eb33ec4..52fc0b42f326 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -25,7 +25,7 @@ import 'package:playground_components/playground_components.dart'; import '../../auth/notifier.dart'; import '../../cache/unit_content.dart'; -import '../../cache/user_progress.dart'; +import '../../cache/unit_progress.dart'; import '../../config.dart'; import '../../models/unit.dart'; import '../../models/unit_content.dart'; @@ -41,7 +41,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { final _appNotifier = GetIt.instance.get(); final _authNotifier = GetIt.instance.get(); final _unitContentCache = GetIt.instance.get(); - final _userProgressCache = GetIt.instance.get(); + final _unitProgressCache = GetIt.instance.get(); UnitContentModel? _currentUnitContent; TourNotifier({ @@ -55,7 +55,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { contentTreeController.addListener(_onUnitChanged); _unitContentCache.addListener(_onUnitChanged); _appNotifier.addListener(_onAppNotifierChanged); - _authNotifier.addListener(_onUserProgressChanged); + _authNotifier.addListener(_onUnitProgressChanged); _onUnitChanged(); } @@ -75,8 +75,8 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { ); } - Future _onUserProgressChanged() async { - await _userProgressCache.updateCompletedUnits(); + Future _onUnitProgressChanged() async { + await _unitProgressCache.updateCompletedUnits(); } void _onAppNotifierChanged() { @@ -84,7 +84,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { if (sdkId != null) { playgroundController.setSdk(Sdk.parseOrCreate(sdkId)); contentTreeController.sdkId = sdkId; - _onUserProgressChanged(); + _onUnitProgressChanged(); } } @@ -188,7 +188,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { _unitContentCache.removeListener(_onUnitChanged); contentTreeController.removeListener(_onUnitChanged); _appNotifier.removeListener(_onAppNotifierChanged); - _authNotifier.removeListener(_onUserProgressChanged); + _authNotifier.removeListener(_onUnitProgressChanged); super.dispose(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart index f9c1090f7494..f29c04a56c5a 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart @@ -21,7 +21,7 @@ import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; -import '../../../cache/user_progress.dart'; +import '../../../cache/unit_progress.dart'; import '../state.dart'; class CompleteUnitButton extends StatelessWidget { @@ -31,13 +31,13 @@ class CompleteUnitButton extends StatelessWidget { @override Widget build(BuildContext context) { final themeData = Theme.of(context); - final userProgressCache = GetIt.instance.get(); + final unitProgressCache = GetIt.instance.get(); return AnimatedBuilder( - animation: userProgressCache, + animation: unitProgressCache, builder: (context, child) { final canComplete = - userProgressCache.canCompleteUnit(tourNotifier.currentUnitId); + unitProgressCache.canCompleteUnit(tourNotifier.currentUnitId); final borderColor = canComplete ? themeData.primaryColor : themeData.disabledColor; final onPressed = canComplete diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart index be6c937b8aa8..df8f014867d8 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart @@ -20,7 +20,7 @@ import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; -import '../../../cache/user_progress.dart'; +import '../../../cache/unit_progress.dart'; import '../../../models/group.dart'; import '../../../models/node.dart'; import 'completeness_indicator.dart'; @@ -57,14 +57,14 @@ class _GroupProgressIndicator extends StatelessWidget { @override Widget build(BuildContext context) { - final userProgressCache = GetIt.instance.get(); + final unitProgressCache = GetIt.instance.get(); return AnimatedBuilder( - animation: userProgressCache, + animation: unitProgressCache, builder: (context, child) { final progress = _getGroupProgress( group.nodes, - userProgressCache.getCompletedUnits(), + unitProgressCache.getCompletedUnits(), ); if (progress == 1) { diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart index 0b693d701022..9952b7f84c28 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart @@ -20,7 +20,7 @@ import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; -import '../../../cache/user_progress.dart'; +import '../../../cache/unit_progress.dart'; import '../../../models/unit.dart'; import '../controllers/content_tree.dart'; import 'completeness_indicator.dart'; @@ -36,7 +36,7 @@ class UnitWidget extends StatelessWidget { @override Widget build(BuildContext context) { - final userProgressCache = GetIt.instance.get(); + final unitProgressCache = GetIt.instance.get(); return AnimatedBuilder( animation: contentTreeController, @@ -54,9 +54,9 @@ class UnitWidget extends StatelessWidget { child: Row( children: [ AnimatedBuilder( - animation: userProgressCache, + animation: unitProgressCache, builder: (context, child) => CompletenessIndicator( - isCompleted: userProgressCache.isUnitCompleted(unit.id), + isCompleted: unitProgressCache.isUnitCompleted(unit.id), isSelected: isSelected, ), ), From 8b639d08b3d6101ba9b13a6f6fe32b7cc7261559 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 1 Dec 2022 12:50:35 +0600 Subject: [PATCH 52/65] all caches extend cache (#23692) --- .../frontend/lib/cache/content_tree.dart | 14 +++++--------- learning/tour-of-beam/frontend/lib/cache/sdk.dart | 13 +++++-------- .../frontend/lib/cache/unit_content.dart | 14 +++++--------- 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/cache/content_tree.dart b/learning/tour-of-beam/frontend/lib/cache/content_tree.dart index 296b9a84238c..b7ce82ac3af3 100644 --- a/learning/tour-of-beam/frontend/lib/cache/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/cache/content_tree.dart @@ -18,21 +18,17 @@ import 'dart:async'; -import 'package:flutter/widgets.dart'; - import '../models/content_tree.dart'; -import '../repositories/client/client.dart'; +import 'cache.dart'; -class ContentTreeCache extends ChangeNotifier { - final TobClient client; +class ContentTreeCache extends Cache { + ContentTreeCache({ + required super.client, + }); final _treesBySdkId = {}; final _futuresBySdkId = >{}; - ContentTreeCache({ - required this.client, - }); - ContentTreeModel? getContentTree(String sdkId) { final future = _futuresBySdkId[sdkId]; if (future == null) { diff --git a/learning/tour-of-beam/frontend/lib/cache/sdk.dart b/learning/tour-of-beam/frontend/lib/cache/sdk.dart index 068fda06b765..8b26a3c1805b 100644 --- a/learning/tour-of-beam/frontend/lib/cache/sdk.dart +++ b/learning/tour-of-beam/frontend/lib/cache/sdk.dart @@ -18,22 +18,19 @@ import 'dart:async'; -import 'package:flutter/widgets.dart'; import 'package:playground_components/playground_components.dart'; -import '../repositories/client/client.dart'; import '../repositories/models/get_sdks_response.dart'; +import 'cache.dart'; -class SdkCache extends ChangeNotifier { - final TobClient client; +class SdkCache extends Cache { + SdkCache({ + required super.client, + }); final _sdks = []; Future? _future; - SdkCache({ - required this.client, - }); - List getSdks() { if (_future == null) { unawaited(_loadSdks()); diff --git a/learning/tour-of-beam/frontend/lib/cache/unit_content.dart b/learning/tour-of-beam/frontend/lib/cache/unit_content.dart index 25d703064808..d8499a641e27 100644 --- a/learning/tour-of-beam/frontend/lib/cache/unit_content.dart +++ b/learning/tour-of-beam/frontend/lib/cache/unit_content.dart @@ -18,21 +18,17 @@ import 'dart:async'; -import 'package:flutter/widgets.dart'; - import '../models/unit_content.dart'; -import '../repositories/client/client.dart'; +import 'cache.dart'; -class UnitContentCache extends ChangeNotifier { - final TobClient client; +class UnitContentCache extends Cache { + UnitContentCache({ + required super.client, + }); final _unitContents = >{}; final _futures = >>{}; - UnitContentCache({ - required this.client, - }); - UnitContentModel? getUnitContent(String sdkId, String unitId) { final future = _futures[sdkId]?[unitId]; if (future == null) { From c8db1ef778f401a9029c113a784faeb94919d660 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 1 Dec 2022 13:05:12 +0600 Subject: [PATCH 53/65] refined open overlay (#23692) --- .../frontend/lib/components/login/button.dart | 10 +++++++--- .../lib/components/profile/avatar.dart | 14 +++++++++----- .../lib/playground_components.dart | 5 +++-- .../{open_overlay.dart => overlay/opener.dart} | 18 +++++++----------- 4 files changed, 26 insertions(+), 21 deletions(-) rename playground/frontend/playground_components/lib/src/widgets/{open_overlay.dart => overlay/opener.dart} (78%) diff --git a/learning/tour-of-beam/frontend/lib/components/login/button.dart b/learning/tour-of-beam/frontend/lib/components/login/button.dart index 42da3298783c..2fb2038d6bfd 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/button.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/button.dart @@ -31,9 +31,13 @@ class LoginButton extends StatelessWidget { onPressed: () { final closeNotifier = PublicNotifier(); openOverlay( - context, - closeNotifier, - LoginContent(onLoggedIn: closeNotifier.notifyPublic), + context: context, + closeNotifier: closeNotifier, + positioned: Positioned( + right: BeamSizes.size10, + top: BeamSizes.appBarHeight, + child: LoginContent(onLoggedIn: closeNotifier.notifyPublic), + ), ); }, child: const Text('ui.signIn').tr(), diff --git a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart index fd72518897e4..d4b88584dab6 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart @@ -33,11 +33,15 @@ class Avatar extends StatelessWidget { onTap: () { final closeNotifier = PublicNotifier(); openOverlay( - context, - closeNotifier, - UserMenu( - closeOverlayCallback: closeNotifier.notifyPublic, - user: user, + context: context, + closeNotifier: closeNotifier, + positioned: Positioned( + right: BeamSizes.size10, + top: BeamSizes.appBarHeight, + child: UserMenu( + closeOverlayCallback: closeNotifier.notifyPublic, + user: user, + ), ), ); }, diff --git a/playground/frontend/playground_components/lib/playground_components.dart b/playground/frontend/playground_components/lib/playground_components.dart index b5c4585e89a0..048559215f63 100644 --- a/playground/frontend/playground_components/lib/playground_components.dart +++ b/playground/frontend/playground_components/lib/playground_components.dart @@ -64,13 +64,14 @@ export 'src/util/pipeline_options.dart'; export 'src/widgets/bubble.dart'; export 'src/widgets/clickable.dart'; export 'src/widgets/complexity.dart'; -export 'src/widgets/dismissible_overlay.dart'; export 'src/widgets/divider.dart'; export 'src/widgets/header_icon_button.dart'; export 'src/widgets/loading_indicator.dart'; export 'src/widgets/logo.dart'; -export 'src/widgets/open_overlay.dart'; export 'src/widgets/output/output.dart'; +export 'src/widgets/overlay/body.dart'; +export 'src/widgets/overlay/dismissible.dart'; +export 'src/widgets/overlay/opener.dart'; export 'src/widgets/reset_button.dart'; export 'src/widgets/run_or_cancel_button.dart'; export 'src/widgets/shortcut_tooltip.dart'; diff --git a/playground/frontend/playground_components/lib/src/widgets/open_overlay.dart b/playground/frontend/playground_components/lib/src/widgets/overlay/opener.dart similarity index 78% rename from playground/frontend/playground_components/lib/src/widgets/open_overlay.dart rename to playground/frontend/playground_components/lib/src/widgets/overlay/opener.dart index 30749d7b522b..aebfded5d6d6 100644 --- a/playground/frontend/playground_components/lib/src/widgets/open_overlay.dart +++ b/playground/frontend/playground_components/lib/src/widgets/overlay/opener.dart @@ -17,22 +17,18 @@ */ import 'package:flutter/material.dart'; -import 'package:playground_components/playground_components.dart'; +import '../../../playground_components.dart'; -void openOverlay( - BuildContext context, - PublicNotifier closeNotifier, - Widget child, -) { +void openOverlay({ + required BuildContext context, + required PublicNotifier closeNotifier, + required Positioned positioned, +}) { final overlay = OverlayEntry( builder: (context) { return DismissibleOverlay( close: closeNotifier.notifyPublic, - child: Positioned( - right: BeamSizes.size10, - top: BeamSizes.appBarHeight, - child: child, - ), + child: positioned, ); }, ); From 869b40cefa9222b5a61db0125f6c54340dfc918c Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 1 Dec 2022 13:06:40 +0600 Subject: [PATCH 54/65] extracted overlay body (#23692) --- .../lib/components/login/content.dart | 53 +++++++------------ .../lib/components/profile/user_menu.dart | 40 +++++--------- .../lib/src/widgets/overlay/body.dart | 18 +++++++ 3 files changed, 50 insertions(+), 61 deletions(-) create mode 100644 playground/frontend/playground_components/lib/src/widgets/overlay/body.dart diff --git a/learning/tour-of-beam/frontend/lib/components/login/content.dart b/learning/tour-of-beam/frontend/lib/components/login/content.dart index 23a8971c96e6..1fb4e4231056 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/content.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/content.dart @@ -36,43 +36,28 @@ class LoginContent extends StatelessWidget { @override Widget build(BuildContext context) { - return _Body( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'ui.signIn', - style: Theme.of(context).textTheme.titleLarge, - ).tr(), - const SizedBox(height: BeamSizes.size10), - const Text( - 'dialogs.signInIf', - textAlign: TextAlign.center, - ).tr(), - const _Divider(), - _BrandedLoginButtons( - onLoggedIn: onLoggedIn, - ), - ], - ), - ); - } -} - -class _Body extends StatelessWidget { - final Widget child; - - const _Body({required this.child}); - - @override - Widget build(BuildContext context) { - return Material( - elevation: BeamSizes.size10, - borderRadius: BorderRadius.circular(10), + return OverlayBody( child: Container( width: TobSizes.authOverlayWidth, padding: const EdgeInsets.all(BeamSizes.size24), - child: child, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'ui.signIn', + style: Theme.of(context).textTheme.titleLarge, + ).tr(), + const SizedBox(height: BeamSizes.size10), + const Text( + 'dialogs.signInIf', + textAlign: TextAlign.center, + ).tr(), + const _Divider(), + _BrandedLoginButtons( + onLoggedIn: onLoggedIn, + ), + ], + ), ), ); } diff --git a/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart index 50be01de0a97..47b79b1a73b0 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart @@ -38,34 +38,20 @@ class UserMenu extends StatelessWidget { @override Widget build(BuildContext context) { - return _Body( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _Info(user: user), - const BeamDivider(), - _Buttons( - closeOverlayCallback: closeOverlayCallback, - ), - ], - ), - ); - } -} - -class _Body extends StatelessWidget { - final Widget child; - - const _Body({required this.child}); - - @override - Widget build(BuildContext context) { - return Material( - elevation: BeamSizes.size10, - borderRadius: BorderRadius.circular(10), - child: SizedBox( + return OverlayBody( + child: Container( width: TobSizes.authOverlayWidth, - child: child, + padding: const EdgeInsets.all(BeamSizes.size24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _Info(user: user), + const BeamDivider(), + _Buttons( + closeOverlayCallback: closeOverlayCallback, + ), + ], + ), ), ); } diff --git a/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart b/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart new file mode 100644 index 000000000000..7a6984a5351e --- /dev/null +++ b/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; + +import '../../../playground_components.dart'; + +class OverlayBody extends StatelessWidget { + final Widget child; + + const OverlayBody({required this.child}); + + @override + Widget build(BuildContext context) { + return Material( + elevation: BeamSizes.size10, + borderRadius: BorderRadius.circular(BeamSizes.size10), + child: child, + ); + } +} From 9720c134b5733fb439ae2b4df12bff07c359a95b Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 1 Dec 2022 13:06:57 +0600 Subject: [PATCH 55/65] moved dismissible overlay (#23692) --- .../{dismissible_overlay.dart => overlay/dismissible.dart} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename playground/frontend/playground_components/lib/src/widgets/{dismissible_overlay.dart => overlay/dismissible.dart} (97%) diff --git a/playground/frontend/playground_components/lib/src/widgets/dismissible_overlay.dart b/playground/frontend/playground_components/lib/src/widgets/overlay/dismissible.dart similarity index 97% rename from playground/frontend/playground_components/lib/src/widgets/dismissible_overlay.dart rename to playground/frontend/playground_components/lib/src/widgets/overlay/dismissible.dart index 2119c5314c7e..e32e55c56a71 100644 --- a/playground/frontend/playground_components/lib/src/widgets/dismissible_overlay.dart +++ b/playground/frontend/playground_components/lib/src/widgets/overlay/dismissible.dart @@ -19,7 +19,7 @@ import 'package:flutter/material.dart'; class DismissibleOverlay extends StatelessWidget { - final void Function() close; + final VoidCallback close; final Positioned child; const DismissibleOverlay({ From 9e1bbb081c575358445750694d27e393ebd72406 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 1 Dec 2022 14:02:46 +0600 Subject: [PATCH 56/65] specific imports (#23692) --- .../playground_components/lib/src/widgets/overlay/body.dart | 2 +- .../playground_components/lib/src/widgets/overlay/opener.dart | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart b/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart index 7a6984a5351e..e0ae90aab5b6 100644 --- a/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart +++ b/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../../../playground_components.dart'; +import '../../constants/sizes.dart'; class OverlayBody extends StatelessWidget { final Widget child; diff --git a/playground/frontend/playground_components/lib/src/widgets/overlay/opener.dart b/playground/frontend/playground_components/lib/src/widgets/overlay/opener.dart index aebfded5d6d6..cb4e107f5f02 100644 --- a/playground/frontend/playground_components/lib/src/widgets/overlay/opener.dart +++ b/playground/frontend/playground_components/lib/src/widgets/overlay/opener.dart @@ -17,7 +17,9 @@ */ import 'package:flutter/material.dart'; -import '../../../playground_components.dart'; + +import '../../controllers/public_notifier.dart'; +import 'dismissible.dart'; void openOverlay({ required BuildContext context, From af936d0b115bf42f21310719dc1b18e580010421 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 1 Dec 2022 14:59:52 +0600 Subject: [PATCH 57/65] added firebase_options.dart into gradle rat exclusions & added a missing license (#23692) --- build.gradle.kts | 1 + .../lib/src/widgets/overlay/body.dart | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index db571d616c6b..d550c9745b94 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -164,6 +164,7 @@ tasks.rat { "learning/tour-of-beam/frontend/**/*.gen.dart", "learning/tour-of-beam/frontend/.metadata", "learning/tour-of-beam/frontend/pubspec.lock", + "learning/tour-of-beam/frontend/lib/firebase_options.dart", // Ignore .gitkeep file "**/.gitkeep", diff --git a/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart b/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart index e0ae90aab5b6..5a45c0bcd304 100644 --- a/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart +++ b/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart @@ -1,3 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import 'package:flutter/material.dart'; import '../../constants/sizes.dart'; From d060372f844b0fa0783b1c175fc893afca0fe0b0 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Tue, 6 Dec 2022 13:46:19 +0600 Subject: [PATCH 58/65] removed padding from user menu (#23692) --- .../frontend/lib/components/profile/user_menu.dart | 3 +-- .../lib/pages/tour/widgets/completeness_indicator.dart | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart index 47b79b1a73b0..5fb49fa7192b 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart @@ -39,9 +39,8 @@ class UserMenu extends StatelessWidget { @override Widget build(BuildContext context) { return OverlayBody( - child: Container( + child: SizedBox( width: TobSizes.authOverlayWidth, - padding: const EdgeInsets.all(BeamSizes.size24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/completeness_indicator.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/completeness_indicator.dart index 4714e0dcbc2e..c75eeaf1bb39 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/completeness_indicator.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/completeness_indicator.dart @@ -20,7 +20,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:playground_components/playground_components.dart'; -import '../../../generated/assets.gen.dart'; +import '../../../assets/assets.gen.dart'; class CompletenessIndicator extends StatelessWidget { final bool isCompleted; From a988404ea868c731984e160ae2f0ab150833669b Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Wed, 7 Dec 2022 15:50:40 +0600 Subject: [PATCH 59/65] documentation update (#23692) --- learning/tour-of-beam/frontend/README.md | 53 ++++++++++++------- .../lib/src/controllers/public_notifier.dart | 4 ++ 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/learning/tour-of-beam/frontend/README.md b/learning/tour-of-beam/frontend/README.md index 2e27a05ad163..a74010993e85 100644 --- a/learning/tour-of-beam/frontend/README.md +++ b/learning/tour-of-beam/frontend/README.md @@ -17,47 +17,62 @@ under the License. --> - # Tour of Beam - These are the main sources of the Tour of Beam website. +# Tour of Beam - # About +These are the main sources of the Tour of Beam website. + +# About ## Getting started + Running, debugging, and testing all require this first step that fetches dependencies and generates code: ```bash cd ../../../playground/frontend/playground_components flutter pub get -flutter pub run build_runner build cd ../../../learning/tour-of-beam/frontend flutter pub get -flutter pub run build_runner build ``` +### Code Generation + +This project relies on generated code for some functionality: +deserializers, constants for asset files, Firebase configuration, etc. + +All generated files are version-controlled, so after checkout the project is immediately runnable. +However, after changes you may need to re-run code generation: +`flutter pub run build_runner build` + +Manual for re-configuring Firebase: +https://firebase.google.com/docs/flutter/setup?platform=web + ### Run The following command is used to build and serve the frontend app locally: `$ flutter run -d chrome` +# Deployment + +# Tests + +Install ChromeDriver to run integration tests in a browser: https://docs.flutter.dev/testing/integration-tests#running-in-a-browser +Run integration tests: +flutter drive \ + --driver=test_driver/integration_test.dart \ + --target=integration_test/counter_test.dart \ + -d web-server - # Deployment +# Packages - # Tests - Install ChromeDriver to run integration tests in a browser: https://docs.flutter.dev/testing/integration-tests#running-in-a-browser - Run integration tests: - flutter drive \ - --driver=test_driver/integration_test.dart \ - --target=integration_test/counter_test.dart \ - -d web-server +`flutter pub get` - # Packages - `flutter pub get` +# Contribution guide - # Contribution guide - For checks: `./gradlew rat` +For checks: `./gradlew rat` +Exclusions for file checks can be added in the Tour of Beam section of this file: `beam/build.gradle.kts` - # Additional resources +# Additional resources - # Troubleshooting +# Troubleshooting diff --git a/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart b/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart index 5744d304da8b..cbc30fe84b9d 100644 --- a/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart +++ b/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart @@ -18,6 +18,10 @@ import 'package:flutter/material.dart'; +/// Exposes notifyListeners that was protected in the superclass. +/// +/// Use this object when you need to fire callbacks that for some +/// reason cannot listen to the object you write your code in. class PublicNotifier extends ChangeNotifier { void notifyPublic() => notifyListeners(); } From d8b5c11ce87fffa989e1d9488b11fc4c5f946641 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 6 Jan 2023 09:37:34 +0600 Subject: [PATCH 60/65] removed goToContextLine set sdk in UserSharedExampleLoadingDescriptor removed jsonDecode from temporary postUnitComplete (#23692) --- .../frontend/lib/pages/tour/state.dart | 23 +++++++++++-------- .../pages/tour/widgets/playground_demo.dart | 1 - .../client/cloud_functions_client.dart | 3 +-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 44fc9b5e23ef..5113397a8c28 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -123,16 +123,19 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { return; } - await playgroundController.examplesLoader.load( - ExamplesLoadingDescriptor( - descriptors: [ - UserSharedExampleLoadingDescriptor( - sdk: sdk, - snippetId: taskSnippetId, - ), - ], - ), - ); + final sdk = Sdk.tryParse(_appNotifier.sdkId); + if (sdk != null) { + await playgroundController.examplesLoader.load( + ExamplesLoadingDescriptor( + descriptors: [ + UserSharedExampleLoadingDescriptor( + sdk: sdk, + snippetId: taskSnippetId, + ), + ], + ), + ); + } } // TODO(alexeyinkin): Hide the entire right pane instead. diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/playground_demo.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/playground_demo.dart index 4b5347a24810..c8016a120caf 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/playground_demo.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/playground_demo.dart @@ -48,7 +48,6 @@ class PlaygroundDemoWidget extends StatelessWidget { first: SnippetEditor( controller: snippetController, isEditable: true, - goToContextLine: false, ), second: OutputWidget( playgroundController: playgroundController, diff --git a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart index 4295115c8a4d..8986de435290 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart @@ -92,7 +92,7 @@ class CloudFunctionsTobClient extends TobClient { @override Future postUnitComplete(String sdkId, String id) async { final token = await GetIt.instance.get().getToken(); - final json = await http.post( + await http.post( Uri.parse( '$cloudFunctionsBaseUrl/postUnitComplete?sdk=$sdkId&id=$id', ), @@ -100,6 +100,5 @@ class CloudFunctionsTobClient extends TobClient { HttpHeaders.authorizationHeader: 'Bearer $token', }, ); - final map = jsonDecode(utf8.decode(json.bodyBytes)); } } From ff8d32b7a6ff9f3790a94a6f4c042527f2772ae6 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 6 Jan 2023 10:29:50 +0600 Subject: [PATCH 61/65] sdk getter (#23692) --- learning/tour-of-beam/frontend/lib/pages/tour/state.dart | 6 +++--- learning/tour-of-beam/frontend/lib/state.dart | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 5113397a8c28..48a6dfc3215a 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -123,13 +123,13 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { return; } - final sdk = Sdk.tryParse(_appNotifier.sdkId); - if (sdk != null) { + final selectedSdk = _appNotifier.sdk; + if (selectedSdk != null) { await playgroundController.examplesLoader.load( ExamplesLoadingDescriptor( descriptors: [ UserSharedExampleLoadingDescriptor( - sdk: sdk, + sdk: selectedSdk, snippetId: taskSnippetId, ), ], diff --git a/learning/tour-of-beam/frontend/lib/state.dart b/learning/tour-of-beam/frontend/lib/state.dart index df87c21838d7..5c5f921bb02e 100644 --- a/learning/tour-of-beam/frontend/lib/state.dart +++ b/learning/tour-of-beam/frontend/lib/state.dart @@ -19,6 +19,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:playground_components/playground_components.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'constants/storage_keys.dart'; @@ -31,6 +32,7 @@ class AppNotifier extends ChangeNotifier { } String? get sdkId => _sdkId; + Sdk? get sdk => Sdk.tryParse(_sdkId); set sdkId(String? newValue) { _sdkId = newValue; From 256d7b733bbae746a16f2aa6296bb0f7db24f397 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 6 Jan 2023 11:02:21 +0600 Subject: [PATCH 62/65] todo: remove sdkId getter and setter (#23692) --- learning/tour-of-beam/frontend/lib/state.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/learning/tour-of-beam/frontend/lib/state.dart b/learning/tour-of-beam/frontend/lib/state.dart index 5c5f921bb02e..c67b037d8d92 100644 --- a/learning/tour-of-beam/frontend/lib/state.dart +++ b/learning/tour-of-beam/frontend/lib/state.dart @@ -31,6 +31,7 @@ class AppNotifier extends ChangeNotifier { unawaited(_readSdkId()); } + // TODO(nausharipov): remove sdkId getter and setter String? get sdkId => _sdkId; Sdk? get sdk => Sdk.tryParse(_sdkId); From 6dd0a3bde117b279320fdeb6aaee9ddd611ae8a0 Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 6 Jan 2023 11:23:29 +0600 Subject: [PATCH 63/65] todo: add unit and integration tests (#23692) --- ...est_screen_wrapper.dart => main_test.dart} | 23 +---------- .../frontend/test/overflow_test.dart | 38 ------------------- 2 files changed, 2 insertions(+), 59 deletions(-) rename learning/tour-of-beam/frontend/test/{common/test_screen_wrapper.dart => main_test.dart} (57%) delete mode 100644 learning/tour-of-beam/frontend/test/overflow_test.dart diff --git a/learning/tour-of-beam/frontend/test/common/test_screen_wrapper.dart b/learning/tour-of-beam/frontend/test/main_test.dart similarity index 57% rename from learning/tour-of-beam/frontend/test/common/test_screen_wrapper.dart rename to learning/tour-of-beam/frontend/test/main_test.dart index 8146e336c3df..b68d73ad670a 100644 --- a/learning/tour-of-beam/frontend/test/common/test_screen_wrapper.dart +++ b/learning/tour-of-beam/frontend/test/main_test.dart @@ -16,25 +16,6 @@ * limitations under the License. */ -import 'package:flutter/material.dart'; -import 'package:playground_components/playground_components.dart'; -import 'package:provider/provider.dart'; - -class TestScreenWrapper extends StatelessWidget { - final Widget child; - const TestScreenWrapper({required this.child}); - - @override - Widget build(BuildContext context) { - return ThemeSwitchNotifierProvider( - child: Consumer( - builder: (context, themeSwitchNotifier, _) { - return MaterialApp( - theme: kLightTheme, - home: child, - ); - }, - ), - ); - } +void main() { + // TODO(nausharipov): add unit and integration tests } diff --git a/learning/tour-of-beam/frontend/test/overflow_test.dart b/learning/tour-of-beam/frontend/test/overflow_test.dart deleted file mode 100644 index 7559b7c5d25e..000000000000 --- a/learning/tour-of-beam/frontend/test/overflow_test.dart +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:tour_of_beam/locator.dart'; -import 'package:tour_of_beam/pages/tour/screen.dart'; -import 'package:tour_of_beam/pages/tour/state.dart'; -import 'common/test_screen_wrapper.dart'; - -void main() async { - await initializeServiceLocator(); - - testWidgets('WelcomeScreen overflow', (tester) async { - tester.binding.window.physicalSizeTestValue = const Size(500, 296); - // TODO(nausharipov): fix the failure - await tester.pumpWidget( - TestScreenWrapper( - child: TourScreen(TourNotifier(initialSdkId: '')), - ), - ); - }); -} From fddeaeea4ac377fd087396433fee10ed008079db Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Fri, 6 Jan 2023 12:09:18 +0600 Subject: [PATCH 64/65] updated readme (#23692) --- learning/tour-of-beam/frontend/README.md | 39 +++++++++++++----------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/learning/tour-of-beam/frontend/README.md b/learning/tour-of-beam/frontend/README.md index a74010993e85..492548c82960 100644 --- a/learning/tour-of-beam/frontend/README.md +++ b/learning/tour-of-beam/frontend/README.md @@ -25,33 +25,38 @@ These are the main sources of the Tour of Beam website. ## Getting started -Running, debugging, and testing all require this first step that fetches -dependencies and generates code: - -```bash -cd ../../../playground/frontend/playground_components -flutter pub get -cd ../../../learning/tour-of-beam/frontend -flutter pub get -``` - -### Code Generation - This project relies on generated code for some functionality: -deserializers, constants for asset files, Firebase configuration, etc. +deserializers, test mocks, constants for asset files, +extracted Beam symbols for the editor, etc. All generated files are version-controlled, so after checkout the project is immediately runnable. However, after changes you may need to re-run code generation: -`flutter pub run build_runner build` -Manual for re-configuring Firebase: -https://firebase.google.com/docs/flutter/setup?platform=web +```bash +cd beam +./gradlew :playground:frontend:playground_components:generateCode +cd learning/tour-of-beam/frontend +flutter pub run build_runner build +``` ### Run The following command is used to build and serve the frontend app locally: -`$ flutter run -d chrome` +```bash +flutter run -d chrome +``` + +### Backend Selection + +To change the Google Project that is used as the backend: + +1. Update Firebase configuration: + https://firebase.google.com/docs/flutter/setup?platform=web + +2. In `/lib/config.dart`, update: + 1. Google Project ID and region. + 2. Playground's backend URLs. # Deployment From f33a4c20fcb547e42edbf5f687cb95d6553de4bc Mon Sep 17 00:00:00 2001 From: "darkhan.nausharipov" Date: Thu, 12 Jan 2023 15:04:54 +0600 Subject: [PATCH 65/65] addressing comments (#23692) --- learning/tour-of-beam/frontend/README.md | 2 +- .../frontend/lib/auth/method.dart | 27 --- .../frontend/lib/auth/method.g.dart | 162 ------------------ .../frontend/lib/auth/notifier.dart | 11 +- .../frontend/lib/cache/cache.dart | 1 + .../frontend/lib/cache/content_tree.dart | 3 +- .../lib/components/login/content.dart | 4 +- learning/tour-of-beam/frontend/pubspec.lock | 37 +--- learning/tour-of-beam/frontend/pubspec.yaml | 3 +- .../tour-of-beam/frontend/test/main_test.dart | 2 +- 10 files changed, 18 insertions(+), 234 deletions(-) delete mode 100644 learning/tour-of-beam/frontend/lib/auth/method.dart delete mode 100644 learning/tour-of-beam/frontend/lib/auth/method.g.dart diff --git a/learning/tour-of-beam/frontend/README.md b/learning/tour-of-beam/frontend/README.md index 492548c82960..cba80719dfec 100644 --- a/learning/tour-of-beam/frontend/README.md +++ b/learning/tour-of-beam/frontend/README.md @@ -36,7 +36,7 @@ However, after changes you may need to re-run code generation: cd beam ./gradlew :playground:frontend:playground_components:generateCode cd learning/tour-of-beam/frontend -flutter pub run build_runner build +flutter pub run build_runner build --delete-conflicting-outputs ``` ### Run diff --git a/learning/tour-of-beam/frontend/lib/auth/method.dart b/learning/tour-of-beam/frontend/lib/auth/method.dart deleted file mode 100644 index ccc3d63116d9..000000000000 --- a/learning/tour-of-beam/frontend/lib/auth/method.dart +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import 'package:enum_map/enum_map.dart'; - -part 'method.g.dart'; - -@unmodifiableEnumMap -enum AuthMethod { - google, - github, -} diff --git a/learning/tour-of-beam/frontend/lib/auth/method.g.dart b/learning/tour-of-beam/frontend/lib/auth/method.g.dart deleted file mode 100644 index e9f7c3dfb64b..000000000000 --- a/learning/tour-of-beam/frontend/lib/auth/method.g.dart +++ /dev/null @@ -1,162 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'method.dart'; - -// ************************************************************************** -// UnmodifiableEnumMapGenerator -// ************************************************************************** - -class UnmodifiableAuthMethodMap extends UnmodifiableEnumMap { - final V google; - final V github; - - const UnmodifiableAuthMethodMap({ - required this.google, - required this.github, - }); - - @override - Map cast() { - return Map.castFrom(this); - } - - @override - bool containsValue(Object? value) { - if (this.google == value) return true; - if (this.github == value) return true; - return false; - } - - @override - bool containsKey(Object? key) { - return key.runtimeType == AuthMethod; - } - - @override - V? operator [](Object? key) { - switch (key) { - case AuthMethod.google: - return this.google; - case AuthMethod.github: - return this.github; - } - - return null; - } - - @override - void operator []=(AuthMethod key, V value) { - throw Exception("Cannot modify this map."); - } - - @override - Iterable> get entries { - return [ - MapEntry(AuthMethod.google, this.google), - MapEntry(AuthMethod.github, this.github), - ]; - } - - @override - Map map(MapEntry transform(AuthMethod key, V value)) { - final google = transform(AuthMethod.google, this.google); - final github = transform(AuthMethod.github, this.github); - return { - google.key: google.value, - github.key: github.value, - }; - } - - @override - void addEntries(Iterable> newEntries) { - throw Exception("Cannot modify this map."); - } - - @override - V update(AuthMethod key, V update(V value), {V Function()? ifAbsent}) { - throw Exception("Cannot modify this map."); - } - - @override - void updateAll(V update(AuthMethod key, V value)) { - throw Exception("Cannot modify this map."); - } - - @override - void removeWhere(bool test(AuthMethod key, V value)) { - throw Exception("Objects in this map cannot be removed."); - } - - @override - V putIfAbsent(AuthMethod key, V ifAbsent()) { - return this.get(key); - } - - @override - void addAll(Map other) { - throw Exception("Cannot modify this map."); - } - - @override - V? remove(Object? key) { - throw Exception("Objects in this map cannot be removed."); - } - - @override - void clear() { - throw Exception("Objects in this map cannot be removed."); - } - - @override - void forEach(void action(AuthMethod key, V value)) { - action(AuthMethod.google, this.google); - action(AuthMethod.github, this.github); - } - - @override - Iterable get keys { - return AuthMethod.values; - } - - @override - Iterable get values { - return [ - this.google, - this.github, - ]; - } - - @override - int get length { - return 2; - } - - @override - bool get isEmpty { - return false; - } - - @override - bool get isNotEmpty { - return true; - } - - V get(AuthMethod key) { - switch (key) { - case AuthMethod.google: - return this.google; - case AuthMethod.github: - return this.github; - } - } - - @override - String toString() { - final buffer = StringBuffer("{"); - buffer.write("AuthMethod.google: ${this.google}"); - buffer.write(", "); - buffer.write("AuthMethod.github: ${this.github}"); - buffer.write("}"); - return buffer.toString(); - } -} diff --git a/learning/tour-of-beam/frontend/lib/auth/notifier.dart b/learning/tour-of-beam/frontend/lib/auth/notifier.dart index c6b147ad02d0..2eb7be819f39 100644 --- a/learning/tour-of-beam/frontend/lib/auth/notifier.dart +++ b/learning/tour-of-beam/frontend/lib/auth/notifier.dart @@ -19,15 +19,10 @@ import 'dart:async'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart'; import 'package:flutter/material.dart'; -import 'method.dart'; class AuthNotifier extends ChangeNotifier { - final _authProviders = UnmodifiableAuthMethodMap( - google: GoogleAuthProvider(), - github: GithubAuthProvider(), - ); - AuthNotifier() { FirebaseAuth.instance.authStateChanges().listen((user) { notifyListeners(); @@ -40,8 +35,8 @@ class AuthNotifier extends ChangeNotifier { return await FirebaseAuth.instance.currentUser?.getIdToken(); } - Future logIn(AuthMethod authMethod) async { - await FirebaseAuth.instance.signInWithPopup(_authProviders.get(authMethod)); + Future logIn(AuthProvider authProvider) async { + await FirebaseAuth.instance.signInWithPopup(authProvider); } Future logOut() async { diff --git a/learning/tour-of-beam/frontend/lib/cache/cache.dart b/learning/tour-of-beam/frontend/lib/cache/cache.dart index a77876d27023..c11e2790c422 100644 --- a/learning/tour-of-beam/frontend/lib/cache/cache.dart +++ b/learning/tour-of-beam/frontend/lib/cache/cache.dart @@ -20,6 +20,7 @@ import 'package:flutter/material.dart'; import '../repositories/client/client.dart'; +/// A base class for caching entities from network requests. abstract class Cache extends ChangeNotifier { final TobClient client; diff --git a/learning/tour-of-beam/frontend/lib/cache/content_tree.dart b/learning/tour-of-beam/frontend/lib/cache/content_tree.dart index b7ce82ac3af3..5f35af7e55e0 100644 --- a/learning/tour-of-beam/frontend/lib/cache/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/cache/content_tree.dart @@ -30,8 +30,7 @@ class ContentTreeCache extends Cache { final _futuresBySdkId = >{}; ContentTreeModel? getContentTree(String sdkId) { - final future = _futuresBySdkId[sdkId]; - if (future == null) { + if (_futuresBySdkId.containsKey(sdkId)) { unawaited(_loadContentTree(sdkId)); } diff --git a/learning/tour-of-beam/frontend/lib/components/login/content.dart b/learning/tour-of-beam/frontend/lib/components/login/content.dart index 1fb4e4231056..ae1fe80fa028 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/content.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/content.dart @@ -17,13 +17,13 @@ */ import 'package:easy_localization/easy_localization.dart'; +import 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; import '../../assets/assets.gen.dart'; -import '../../auth/method.dart'; import '../../auth/notifier.dart'; import '../../constants/sizes.dart'; @@ -132,7 +132,7 @@ class _BrandedLoginButtons extends StatelessWidget { const SizedBox(height: BeamSizes.size16), ElevatedButton.icon( onPressed: () async { - await authNotifier.logIn(AuthMethod.google); + await authNotifier.logIn(GoogleAuthProvider()); onLoggedIn(); }, style: isLightTheme ? googleLightButtonStyle : darkButtonStyle, diff --git a/learning/tour-of-beam/frontend/pubspec.lock b/learning/tour-of-beam/frontend/pubspec.lock index ce97b23ebec9..0f19f8a44aab 100644 --- a/learning/tour-of-beam/frontend/pubspec.lock +++ b/learning/tour-of-beam/frontend/pubspec.lock @@ -14,7 +14,7 @@ packages: name: _flutterfire_internals url: "https://pub.dartlang.org" source: hosted - version: "1.0.9" + version: "1.0.12" aligned_dialog: dependency: transitive description: @@ -35,7 +35,7 @@ packages: name: app_state url: "https://pub.dartlang.org" source: hosted - version: "0.8.1" + version: "0.8.4" archive: dependency: transitive description: @@ -155,20 +155,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.1" - cloud_firestore_platform_interface: - dependency: transitive - description: - name: cloud_firestore_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "5.9.0" - cloud_firestore_web: - dependency: transitive - description: - name: cloud_firestore_web - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" code_builder: dependency: transitive description: @@ -254,19 +240,12 @@ packages: source: hosted version: "0.0.2" enum_map: - dependency: "direct main" + dependency: transitive description: name: enum_map url: "https://pub.dartlang.org" source: hosted version: "0.2.1" - enum_map_gen: - dependency: "direct dev" - description: - name: enum_map_gen - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" equatable: dependency: "direct dev" description: @@ -303,12 +282,12 @@ packages: source: hosted version: "4.1.4" firebase_auth_platform_interface: - dependency: transitive + dependency: "direct main" description: name: firebase_auth_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "6.11.3" + version: "6.11.7" firebase_auth_web: dependency: transitive description: @@ -322,7 +301,7 @@ packages: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.4.1" firebase_core_platform_interface: dependency: transitive description: @@ -336,7 +315,7 @@ packages: name: firebase_core_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.1.0" fixnum: dependency: transitive description: @@ -355,7 +334,7 @@ packages: name: flutter_code_editor url: "https://pub.dartlang.org" source: hosted - version: "0.2.1" + version: "0.2.5" flutter_driver: dependency: transitive description: flutter diff --git a/learning/tour-of-beam/frontend/pubspec.yaml b/learning/tour-of-beam/frontend/pubspec.yaml index 3813ca17fbd8..0d6a7329edf2 100644 --- a/learning/tour-of-beam/frontend/pubspec.yaml +++ b/learning/tour-of-beam/frontend/pubspec.yaml @@ -32,8 +32,8 @@ dependencies: easy_localization: ^3.0.1 easy_localization_ext: ^0.1.0 easy_localization_loader: ^1.0.0 - enum_map: ^0.2.1 firebase_auth: ^4.1.1 + firebase_auth_platform_interface: ^6.11.7 firebase_core: ^2.1.1 flutter: { sdk: flutter } flutter_markdown: ^0.6.12 @@ -52,7 +52,6 @@ dependencies: dev_dependencies: build_runner: ^2.2.0 - enum_map_gen: ^0.2.0 equatable: ^2.0.5 flutter_gen_runner: ^4.3.0 flutter_test: { sdk: flutter } diff --git a/learning/tour-of-beam/frontend/test/main_test.dart b/learning/tour-of-beam/frontend/test/main_test.dart index b68d73ad670a..dc0b1dd00b03 100644 --- a/learning/tour-of-beam/frontend/test/main_test.dart +++ b/learning/tour-of-beam/frontend/test/main_test.dart @@ -17,5 +17,5 @@ */ void main() { - // TODO(nausharipov): add unit and integration tests + // TODO(nausharipov): add unit and integration tests: // https://github.com/apache/beam/issues/24982 }