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..471bb6734fe6 100644 --- a/learning/tour-of-beam/frontend/lib/models/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/models/content_tree.dart @@ -18,19 +18,29 @@ import '../repositories/models/get_content_tree_response.dart'; import 'module.dart'; +import 'node.dart'; +import 'parent_node.dart'; -class ContentTreeModel { - final String sdkId; +class ContentTreeModel extends ParentNodeModel { final List modules; + String get sdkId => id; + + @override + List get nodes => modules; + const ContentTreeModel({ - required this.sdkId, + required super.id, required this.modules, - }); + }) : super( + parent: null, + title: '', + nodes: modules, + ); ContentTreeModel.fromResponse(GetContentTreeResponse response) : this( - sdkId: response.sdkId, + id: response.sdkId, modules: response.modules .map(ModuleModel.fromResponse) .toList(growable: false), 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..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 @@ -17,33 +17,96 @@ */ 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 = {}; + + Set get expandedIds => _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(); + } + + void expandGroup(GroupModel group) { + _expandedIds.add(group.id); + notifyListeners(); + } + + void collapseGroup(GroupModel group) { + _expandedIds.remove(group.id); + notifyListeners(); + } + + List _getNodeAncestors(NodeModel node, List ancestorIds) { + if (node.parent != null) { + return _getNodeAncestors( + node.parent!, + [...ancestorIds, node.parent!.id], + ); + } + return ancestorIds.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..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 @@ -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; @@ -36,23 +35,32 @@ class GroupWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return ExpansionTileWrapper( - ExpansionTile( - tilePadding: EdgeInsets.zero, - title: GroupTitleWidget( - group: group, - onTap: () => contentTreeController.onNodeTap(group), - ), - childrenPadding: const EdgeInsets.only( - left: BeamSizes.size24, - ), - children: [ - GroupNodesWidget( + return AnimatedBuilder( + animation: contentTreeController, + builder: (context, child) { + final isExpanded = contentTreeController.expandedIds.contains(group.id); + + return StatelessExpansionTile( + isExpanded: isExpanded, + onExpansionChanged: (isExpanding) { + if (isExpanding) { + contentTreeController.expandGroup(group); + } else { + contentTreeController.collapseGroup(group); + } + }, + 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/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/components/filler_text.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart similarity index 52% rename from learning/tour-of-beam/frontend/lib/components/filler_text.dart rename to learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart index ca6099e6d9de..149bd04a586e 100644 --- a/learning/tour-of-beam/frontend/lib/components/filler_text.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/stateless_expansion_tile.dart @@ -17,13 +17,37 @@ */ import 'package:flutter/material.dart'; +import 'package:playground_components/playground_components.dart'; -class FillerText extends StatelessWidget { - final int width; - const FillerText({required this.width}); +import '../../../components/expansion_tile_wrapper.dart'; + +class StatelessExpansionTile extends StatelessWidget { + final bool isExpanded; + final ValueChanged? onExpansionChanged; + final Widget title; + final Widget child; + + const StatelessExpansionTile({ + required this.isExpanded, + required this.onExpansionChanged, + required this.title, + required this.child, + }); @override Widget build(BuildContext context) { - return Text(''.padRight(width, 'Just a filler text. ')); + return ExpansionTileWrapper( + ExpansionTile( + key: ValueKey(isExpanded), + initiallyExpanded: isExpanded, + tilePadding: EdgeInsets.zero, + onExpansionChanged: onExpansionChanged, + title: title, + childrenPadding: const EdgeInsets.only( + left: BeamSizes.size24, + ), + children: [child], + ), + ); } } 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..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 @@ -21,18 +21,30 @@ 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) { + final ext = Theme.of(context).extension()!; + return Padding( padding: const EdgeInsets.only( left: BeamSizes.size4, right: BeamSizes.size8, ), - child: SvgPicture.asset(assetPath), + child: SvgPicture.asset( + assetPath, + color: isSelected + ? 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 914361a347a4..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 @@ -35,17 +35,33 @@ 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)), - ], - ), - ), + return AnimatedBuilder( + animation: contentTreeController, + builder: (context, child) { + final 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), + ), + padding: const EdgeInsets.symmetric(vertical: BeamSizes.size10), + child: Row( + children: [ + TourProgressIndicator( + assetPath: Assets.svg.unitProgress0, + isSelected: isSelected, + ), + Expanded( + child: Text(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 e1ed198ef56a..51fb2a0fd730 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.4" + version: "0.1.8" 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,