Skip to content

Commit

Permalink
Unit content navigation (apache#23593)
Browse files Browse the repository at this point in the history
Update URL on node click (apache#23593)

Active unit color (apache#23593)

removeListener in unit (apache#23593)

First unit is opened on group title click (apache#23593)

WIP by Alexey Inkin (apache#23593)

selectedUnitColor (apache#23593)

Unit borderRadius (apache#23593)

RegExp todo (apache#23593)

added referenced collection package to remove warning (apache#23593)

small refinement (apache#23593)

expand on group tap, padding, openNode (apache#23593)

group expansion bug fix (apache#23593)
  • Loading branch information
darkhan.nausharipov authored and nausharipov committed Nov 4, 2022
1 parent d407b60 commit e0afa9c
Show file tree
Hide file tree
Showing 19 changed files with 259 additions and 98 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 0 additions & 29 deletions learning/tour-of-beam/frontend/lib/components/filler_text.dart

This file was deleted.

14 changes: 12 additions & 2 deletions learning/tour-of-beam/frontend/lib/models/content_tree.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<ModuleModel> modules;

@override
List<NodeModel> get nodes => modules;

const ContentTreeModel({
required this.sdkId,
required this.modules,
});
}) : super(
id: sdkId,
parent: null,
title: '',
nodes: modules,
);

ContentTreeModel.fromResponse(GetContentTreeResponse response)
: this(
Expand Down
29 changes: 21 additions & 8 deletions learning/tour-of-beam/frontend/lib/models/group.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<NodeModel>(
(node) => NodeModel.fromResponse(node, group),
),
);

return group;
}
}
29 changes: 19 additions & 10 deletions learning/tour-of-beam/frontend/lib/models/module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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>(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<NodeModel>(
(node) => NodeModel.fromResponse(node, module),
),
);

return module;
}
}
20 changes: 15 additions & 5 deletions learning/tour-of-beam/frontend/lib/models/node.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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<NodeModel> fromMaps(List json) {
static List<NodeModel> fromMaps(List json, ParentNodeModel parent) {
return json
.cast<Map<String, dynamic>>()
.map<NodeResponseModel>(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<String> treeIds);
}
18 changes: 18 additions & 0 deletions learning/tour-of-beam/frontend/lib/models/parent_node.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,32 @@
* limitations under the License.
*/

import 'package:collection/collection.dart';

import 'node.dart';

abstract class ParentNodeModel extends NodeModel {
final List<NodeModel> nodes;

const ParentNodeModel({
required super.id,
required super.parent,
required super.title,
required this.nodes,
});

@override
NodeModel getFirstUnit() => nodes[0].getFirstUnit();

@override
NodeModel? getNodeByTreeIds(List<String> treeIds) {
final firstId = treeIds.firstOrNull;
final child = nodes.firstWhereOrNull((node) => node.id == firstId);

if (child == null) {
return null;
}

return child.getNodeByTreeIds(treeIds.sublist(1));
}
}
15 changes: 13 additions & 2 deletions learning/tour-of-beam/frontend/lib/models/unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> treeIds) => this;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> _treeIds;
NodeModel? _currentNode;
final _contentTreeCache = GetIt.instance.get<ContentTreeCache>();
final expandedIds = <String>{};

ContentTreeController({
required String initialSdkId,
List<String> 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<String> 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<String> _getNodeAncestors(NodeModel node, List<String> 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();
}
}
9 changes: 7 additions & 2 deletions learning/tour-of-beam/frontend/lib/pages/tour/path.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class TourPath extends PagePath {
final String sdkId;
final List<String> 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,
Expand All @@ -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 <String>[]
// TODO(nausharipov): use RegExp to remove the slash
: treeIdsString.substring(1).split('/');

return TourPath(
sdkId: sdkId,
Expand Down
2 changes: 2 additions & 0 deletions learning/tour-of-beam/frontend/lib/pages/tour/state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin<void> {
playgroundController = _createPlaygroundController(initialSdkId) {
contentTreeController.addListener(_onChanged);
_unitContentCache.addListener(_onChanged);
_onChanged();
}

@override
Expand All @@ -53,6 +54,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin<void> {
);

void _onChanged() {
emitPathChanged();
final currentNode = contentTreeController.currentNode;
if (currentNode is UnitModel) {
final content = _unitContentCache.getUnitContent(
Expand Down
Loading

0 comments on commit e0afa9c

Please sign in to comment.