-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathExplorerBlock.java
More file actions
124 lines (107 loc) · 4.67 KB
/
Copy pathExplorerBlock.java
File metadata and controls
124 lines (107 loc) · 4.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package rsp.compositions.shell;
import rsp.component.ComponentStateSupplier;
import rsp.component.ComponentView;
import rsp.component.EventKey;
import rsp.component.StateUpdater;
import rsp.compositions.composition.Composition;
import rsp.compositions.composition.StructureNode;
import rsp.compositions.block.Block;
import rsp.compositions.block.BlockTarget;
import rsp.compositions.block.NavigationEntry;
import rsp.compositions.block.NavigationNode;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import static rsp.compositions.block.EventKeys.SET_PRIMARY;
/**
* ExplorerBlock - Navigation sidebar block.
* <p>
* Builds a {@link NavigationNode} tree from compositions and a {@link StructureNode} tree,
* and relays menu selection events as {@code SET_PRIMARY} commands.
* <p>
* Register in composition and configure as left sidebar in Layout:
* <pre>{@code
* group.bind(ExplorerBlock.class, () -> new ExplorerBlock(mainBlocks.structureTree()))
* new DefaultLayout().leftSidebar(ExplorerBlock.class)
* }</pre>
*/
public class ExplorerBlock extends Block<ExplorerView.ExplorerViewState, ExplorerView.OpenBlock> {
private final StructureNode structure;
public ExplorerBlock(StructureNode structure) {
this.structure = Objects.requireNonNull(structure);
}
@Override
public String title() {
return "Explorer";
}
@Override
public ComponentStateSupplier<ExplorerView.ExplorerViewState> initStateSupplier() {
return (_, context) -> {
List<Composition> compositions = context.get(rsp.compositions.block.ContextKeys.APP_COMPOSITIONS);
NavigationNode tree = buildNavigationTree(compositions, structure);
String category = categoryFor(context);
return new ExplorerView.ExplorerViewState(tree, category);
};
}
@Override
public ComponentView<ExplorerView.ExplorerViewState, ExplorerView.OpenBlock> componentView() {
return new ExplorerView();
}
@Override
protected void onBlockMounted(ExplorerView.ExplorerViewState state,
StateUpdater<ExplorerView.ExplorerViewState> stateUpdate) {
watch(rsp.compositions.block.ContextKeys.SCENE, (_, scene) ->
stateUpdate.applyStateTransformation(current ->
new ExplorerView.ExplorerViewState(current.tree(), categoryFor(scene))));
}
@Override
protected void onIntent(ExplorerView.OpenBlock intent,
ExplorerView.ExplorerViewState state,
StateUpdater<ExplorerView.ExplorerViewState> stateUpdater) {
lookup().publish(SET_PRIMARY, intent.entry().blockKey());
}
private String categoryFor(rsp.component.ComponentContext context) {
return categoryFor(context.get(rsp.compositions.block.ContextKeys.SCENE));
}
private String categoryFor(rsp.compositions.block.Scene scene) {
return scene == null || scene.routedDescriptor() == null
? null
: structure.labelFor(scene.routedDescriptor().blockKey());
}
private static NavigationNode buildNavigationTree(List<Composition> compositions,
StructureNode node) {
List<NavigationNode> childNodes = new ArrayList<>();
for (StructureNode child : node.children()) {
NavigationNode childNode = buildNavigationTree(compositions, child);
if (childNode != null) {
childNodes.add(childNode);
}
}
NavigationEntry entry = null;
if (node.label() != null && compositions != null) {
for (BlockTarget target : node.blockTargets()) {
Optional<String> routeOpt = findRoute(compositions, target.key());
if (routeOpt.isPresent() && !routeOpt.get().contains(":")) {
entry = new NavigationEntry(node.label(), node.label(), target.key(),
target.blockClass(), routeOpt.get());
break;
}
}
}
if (node.label() == null && entry == null && childNodes.isEmpty()) {
return null;
}
return new NavigationNode(node.label(), entry, List.copyOf(childNodes));
}
private static Optional<String> findRoute(List<Composition> compositions,
Object blockKey) {
for (Composition comp : compositions) {
Optional<String> route = comp.router().findRoutePattern(blockKey);
if (route.isPresent()) {
return route;
}
}
return Optional.empty();
}
}