1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components_ng/pattern/navrouter/navrouter_group_node.h"
17
18 #include "base/memory/ace_type.h"
19 #include "base/memory/referenced.h"
20 #include "base/utils/utils.h"
21 #include "core/components_ng/base/frame_node.h"
22 #include "core/components_ng/base/view_stack_processor.h"
23 #include "core/components_ng/pattern/image/image_layout_property.h"
24 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
25 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
26 #include "core/components_ng/pattern/navigation/navigation_layout_property.h"
27 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
28 #include "core/components_ng/pattern/navigation/title_bar_layout_property.h"
29 #include "core/components_ng/pattern/navigation/title_bar_node.h"
30 #include "core/components_ng/pattern/navrouter/navdestination_event_hub.h"
31 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
32 #include "core/components_ng/pattern/navrouter/navdestination_layout_property.h"
33 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
34 #include "core/components_ng/pattern/navrouter/navrouter_event_hub.h"
35 #include "core/components_v2/inspector/inspector_constants.h"
36
37 namespace OHOS::Ace::NG {
38
GetOrCreateGroupNode(const std::string & tag,int32_t nodeId,const std::function<RefPtr<Pattern> (void)> & patternCreator)39 RefPtr<NavRouterGroupNode> NavRouterGroupNode::GetOrCreateGroupNode(
40 const std::string& tag, int32_t nodeId, const std::function<RefPtr<Pattern>(void)>& patternCreator)
41 {
42 auto frameNode = GetFrameNode(tag, nodeId);
43 CHECK_NULL_RETURN_NOLOG(!frameNode, AceType::DynamicCast<NavRouterGroupNode>(frameNode));
44 auto pattern = patternCreator ? patternCreator() : MakeRefPtr<Pattern>();
45 auto navRouterGroupNode = AceType::MakeRefPtr<NavRouterGroupNode>(tag, nodeId, pattern);
46 navRouterGroupNode->InitializePatternAndContext();
47 ElementRegister::GetInstance()->AddUINode(navRouterGroupNode);
48 return navRouterGroupNode;
49 }
50
AddChildToGroup(const RefPtr<UINode> & child,int32_t slot)51 void NavRouterGroupNode::AddChildToGroup(const RefPtr<UINode>& child, int32_t slot)
52 {
53 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(child);
54 if (navDestination) {
55 SetNavDestinationNode(navDestination);
56 auto navDestinationNode = AceType::DynamicCast<FrameNode>(child);
57 CHECK_NULL_VOID(navDestinationNode);
58 auto navDestinationEventHub =
59 AceType::DynamicCast<NavDestinationEventHub>(navDestinationNode->GetEventHub<EventHub>());
60 CHECK_NULL_VOID(navDestinationEventHub);
61 auto eventHub = GetEventHub<NavRouterEventHub>();
62 CHECK_NULL_VOID(eventHub);
63 navDestinationEventHub->SetOnStateChange(eventHub->GetOnStateChange());
64 return;
65 }
66 UINode::AddChild(child);
67 }
68
DeleteChildFromGroup(int32_t slot)69 void NavRouterGroupNode::DeleteChildFromGroup(int32_t slot)
70 {
71 UINode::RemoveChildAtIndex(slot);
72 }
73
OnDetachFromMainTree()74 void NavRouterGroupNode::OnDetachFromMainTree()
75 {
76 FrameNode::OnDetachFromMainTree();
77 auto parent = GetParent();
78 while (parent) {
79 if (CleanNodeInNavigation(parent)) {
80 return;
81 }
82 parent = parent->GetParent();
83 }
84 }
85
OnAttachToMainTree()86 void NavRouterGroupNode::OnAttachToMainTree()
87 {
88 FrameNode::OnAttachToMainTree();
89 auto parent = GetParent();
90 while (parent) {
91 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(parent);
92 if (navigationNode) {
93 break;
94 }
95 parent = parent->GetParent();
96 }
97 SetDestinationChangeEvent(parent);
98 SetBackButtonEvent(parent);
99 InitNavigationContent(parent);
100 }
101
SetDestinationChangeEvent(const RefPtr<UINode> & parent)102 void NavRouterGroupNode::SetDestinationChangeEvent(const RefPtr<UINode>& parent)
103 {
104 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(parent);
105 CHECK_NULL_VOID(navigationNode);
106 auto onDestinationChange = [weak = WeakClaim(this), navigation = navigationNode]() {
107 auto navRouter = weak.Upgrade();
108 CHECK_NULL_VOID(navRouter);
109 auto layoutProperty = navigation->GetLayoutProperty<NavigationLayoutProperty>();
110 CHECK_NULL_VOID(layoutProperty);
111 if (layoutProperty->GetNavigationModeValue(NavigationMode::AUTO) == NavigationMode::STACK) {
112 layoutProperty->UpdateDestinationChange(true);
113 }
114 navRouter->AddNavDestinationToNavigation(navigation);
115 };
116 auto eventHub = GetEventHub<NavRouterEventHub>();
117 CHECK_NULL_VOID(eventHub);
118 eventHub->SetOnDestinationChange(std::move(onDestinationChange));
119 }
120
InitNavigationContent(const RefPtr<UINode> & parent)121 void NavRouterGroupNode::InitNavigationContent(const RefPtr<UINode>& parent)
122 {
123 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(parent);
124 CHECK_NULL_VOID(navigationNode);
125 auto layoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
126 CHECK_NULL_VOID(layoutProperty);
127 if (navigationNode->IsFirstNavDestination() &&
128 layoutProperty->GetNavigationModeValue(NavigationMode::AUTO) == NavigationMode::SPLIT) {
129 AddNavDestinationToNavigation(parent);
130 auto eventHub = GetEventHub<NavRouterEventHub>();
131 CHECK_NULL_VOID(eventHub);
132 eventHub->FireChangeEvent(true);
133 navigationNode->MarkIsFirstNavDestination(false);
134 }
135 }
136
AddBackButtonIconToNavDestination(const RefPtr<UINode> & parent)137 void NavRouterGroupNode::AddBackButtonIconToNavDestination(const RefPtr<UINode>& parent)
138 {
139 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(parent);
140 CHECK_NULL_VOID(navigationNode);
141 auto navigationLayoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
142 CHECK_NULL_VOID(navigationLayoutProperty);
143 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode());
144 CHECK_NULL_VOID(navDestination);
145 auto navDestinationLayoutProperty = navDestination->GetLayoutProperty<NavDestinationLayoutProperty>();
146 CHECK_NULL_VOID(navDestinationLayoutProperty);
147
148 // back button icon
149 if (navigationLayoutProperty->HasNoPixMap()) {
150 if (navigationLayoutProperty->HasImageSource()) {
151 navDestinationLayoutProperty->UpdateImageSource(navigationLayoutProperty->GetImageSourceValue());
152 }
153 if (navigationLayoutProperty->HasPixelMap()) {
154 navDestinationLayoutProperty->UpdatePixelMap(navigationLayoutProperty->GetPixelMapValue());
155 }
156 navDestinationLayoutProperty->UpdateNoPixMap(navigationLayoutProperty->GetNoPixMapValue());
157 navDestination->MarkModifyDone();
158 }
159 }
160
SetBackButtonEvent(const RefPtr<UINode> & parent)161 void NavRouterGroupNode::SetBackButtonEvent(const RefPtr<UINode>& parent)
162 {
163 AddBackButtonIconToNavDestination(parent);
164 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(parent);
165 CHECK_NULL_VOID(navigationNode);
166 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode());
167 CHECK_NULL_VOID(navDestination);
168 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode());
169 CHECK_NULL_VOID(titleBarNode);
170 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
171 CHECK_NULL_VOID(backButtonNode);
172 auto backButtonEventHub = backButtonNode->GetEventHub<EventHub>();
173 CHECK_NULL_VOID(backButtonEventHub);
174 auto onBackButtonEvent = [navDestination = navDestination,
175 navigation = navigationNode, weak = WeakClaim(this)](GestureEvent& /*info*/) {
176 auto navRouter = weak.Upgrade();
177 CHECK_NULL_VOID(navRouter);
178 auto layoutProperty = navigation->GetLayoutProperty<NavigationLayoutProperty>();
179 CHECK_NULL_VOID(layoutProperty);
180
181 auto destinationContent = navDestination->GetContentNode();
182 if (destinationContent) {
183 auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
184 CHECK_NULL_VOID(navDestinationPattern);
185 auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
186 CHECK_NULL_VOID(shallowBuilder);
187 shallowBuilder->MarkIsExecuteDeepRenderDone(false);
188 destinationContent->Clean();
189 }
190
191 if (layoutProperty->GetNavigationModeValue(NavigationMode::AUTO) == NavigationMode::STACK) {
192 if (navDestination->GetPreNode()) {
193 navRouter->BackToPreNavDestination(navDestination->GetPreNode(), navigation);
194 navRouter->SetOnStateChangeFalse(navDestination, navigation, true);
195 layoutProperty->UpdateDestinationChange(true);
196 return;
197 }
198
199 navRouter->BackToNavBar(navigation);
200 navRouter->SetOnStateChangeFalse(navDestination, navigation, true);
201 layoutProperty->UpdateDestinationChange(false);
202 return;
203 }
204
205 if (layoutProperty->GetNavigationModeValue(NavigationMode::AUTO) == NavigationMode::SPLIT) {
206 if (navDestination->GetPreNode()) {
207 navRouter->BackToPreNavDestination(navDestination->GetPreNode(), navigation);
208 navRouter->SetOnStateChangeFalse(navDestination, navigation, true);
209 layoutProperty->UpdateDestinationChange(false);
210 return;
211 }
212 }
213 navigation->MarkModifyDone();
214 };
215 navDestination->SetNavDestinationBackButtonEvent(onBackButtonEvent);
216 auto clickEvent = AceType::MakeRefPtr<ClickEvent>(std::move(onBackButtonEvent));
217 if (backButtonEventHub->GetGestureEventHub()) {
218 return;
219 }
220 backButtonEventHub->GetOrCreateGestureEventHub()->AddClickEvent(clickEvent);
221 }
222
AddNavDestinationToNavigation(const RefPtr<UINode> & parent)223 void NavRouterGroupNode::AddNavDestinationToNavigation(const RefPtr<UINode>& parent)
224 {
225 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(parent);
226 CHECK_NULL_VOID(navigationNode);
227 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode());
228 CHECK_NULL_VOID(navDestination);
229 auto navigationContentNode = AceType::DynamicCast<FrameNode>(navigationNode->GetContentNode());
230 CHECK_NULL_VOID(navigationContentNode);
231 const auto& children = navigationContentNode->GetChildren();
232 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
233 const auto& childNode = *iter;
234 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(childNode);
235 if (navDestinationNode && navDestinationNode != navDestination) {
236 auto destinationContent = navDestinationNode->GetContentNode();
237 if (destinationContent) {
238 auto navDestinationPattern = navDestinationNode->GetPattern<NavDestinationPattern>();
239 CHECK_NULL_VOID(navDestinationPattern);
240 auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
241 CHECK_NULL_VOID(shallowBuilder);
242 shallowBuilder->MarkIsExecuteDeepRenderDone(false);
243 destinationContent->Clean();
244 }
245 navDestination->SetPreNode(navDestinationNode);
246 SetOnStateChangeFalse(navDestinationNode, parent);
247 break;
248 }
249 }
250
251 auto parentNode = GetParent();
252 while (parentNode) {
253 auto navBarNode = AceType::DynamicCast<NavBarNode>(parentNode);
254 if (navBarNode) {
255 break;
256 }
257 parentNode = parentNode->GetParent();
258 }
259 auto navBarNode = AceType::DynamicCast<NavBarNode>(parentNode);
260 auto layoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
261 CHECK_NULL_VOID(layoutProperty);
262 if (navBarNode && layoutProperty->GetNavigationModeValue(NavigationMode::AUTO) == NavigationMode::SPLIT) {
263 navigationContentNode->Clean();
264 navigationContentNode->AddChild(navDestination);
265 navigationContentNode->MarkModifyDone();
266 navigationContentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
267 return;
268 }
269
270 SetBackButtonVisible(navDestination);
271 navigationContentNode->Clean();
272 navigationContentNode->AddChild(navDestination);
273 navigationContentNode->MarkModifyDone();
274 navigationContentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
275 }
276
SetOnStateChangeFalse(const RefPtr<UINode> & preNavDestination,const RefPtr<UINode> & navigation,bool isBackButton)277 void NavRouterGroupNode::SetOnStateChangeFalse(
278 const RefPtr<UINode>& preNavDestination, const RefPtr<UINode>& navigation, bool isBackButton)
279 {
280 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(navigation);
281 CHECK_NULL_VOID(navigationNode);
282 auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationNode->GetNavBarNode());
283 CHECK_NULL_VOID(navBarNode);
284 auto navBarContentNode = navBarNode->GetNavBarContentNode();
285 CHECK_NULL_VOID(navBarContentNode);
286 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode());
287 CHECK_NULL_VOID(navDestination);
288 if (!isBackButton && navDestination == preNavDestination) {
289 return;
290 }
291
292 if (isBackButton) {
293 auto newDestiantion = AceType::DynamicCast<FrameNode>(navDestination->GetPreNode());
294 CHECK_NULL_VOID(newDestiantion);
295 auto newEventHub = newDestiantion->GetEventHub<NavDestinationEventHub>();
296 CHECK_NULL_VOID(newEventHub);
297 newEventHub->FireChangeEvent(true);
298 }
299
300 auto preNavDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(preNavDestination);
301 CHECK_NULL_VOID(preNavDestinationNode);
302 auto eventHub = preNavDestinationNode->GetEventHub<NavDestinationEventHub>();
303 CHECK_NULL_VOID(eventHub);
304 eventHub->FireChangeEvent(false);
305 }
306
BackToNavBar(const RefPtr<UINode> & parent)307 void NavRouterGroupNode::BackToNavBar(const RefPtr<UINode>& parent)
308 {
309 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(parent);
310 CHECK_NULL_VOID(navigationNode);
311 auto navigationContentNode = AceType::DynamicCast<FrameNode>(navigationNode->GetContentNode());
312 CHECK_NULL_VOID(navigationContentNode);
313 navigationContentNode->Clean();
314 navigationContentNode->MarkModifyDone();
315 navigationContentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
316 }
317
BackToPreNavDestination(const RefPtr<UINode> & preNavDestination,const RefPtr<UINode> & navigation)318 void NavRouterGroupNode::BackToPreNavDestination(
319 const RefPtr<UINode>& preNavDestination, const RefPtr<UINode>& navigation)
320 {
321 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(navigation);
322 CHECK_NULL_VOID(navigationNode);
323 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNavDestination);
324 CHECK_NULL_VOID(navDestination);
325 auto navigationContentNode = AceType::DynamicCast<FrameNode>(navigationNode->GetContentNode());
326 CHECK_NULL_VOID(navigationContentNode);
327 navigationContentNode->Clean();
328 navigationContentNode->AddChild(navDestination);
329 navigationContentNode->MarkModifyDone();
330 navigationContentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
331 }
332
CleanNodeInNavigation(const RefPtr<UINode> & parent)333 bool NavRouterGroupNode::CleanNodeInNavigation(const RefPtr<UINode>& parent)
334 {
335 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(parent);
336 CHECK_NULL_RETURN(navigationNode, false);
337 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode());
338 CHECK_NULL_RETURN(navDestination, false);
339 auto navigationContentNode = navigationNode->GetContentNode();
340 CHECK_NULL_RETURN(navigationContentNode, false);
341
342 const auto& children = navigationContentNode->GetChildren();
343 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
344 const auto& childNode = *iter;
345 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(childNode);
346 if (navDestinationNode == navDestination) {
347 navigationContentNode->RemoveChildAtIndex(navDestinationNode);
348 return true;
349 }
350 }
351 return false;
352 }
353
SetBackButtonVisible(const RefPtr<UINode> & navDestination)354 void NavRouterGroupNode::SetBackButtonVisible(const RefPtr<UINode>& navDestination)
355 {
356 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(navDestination);
357 CHECK_NULL_VOID(navDestination);
358 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestinationNode->GetTitleBarNode());
359 CHECK_NULL_VOID(titleBarNode);
360 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
361 CHECK_NULL_VOID(titleBarLayoutProperty);
362 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
363 CHECK_NULL_VOID(backButtonNode);
364 auto backButtonLayoutProperty = backButtonNode->GetLayoutProperty<ImageLayoutProperty>();
365 CHECK_NULL_VOID(backButtonLayoutProperty);
366 backButtonLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
367 backButtonNode->MarkModifyDone();
368 }
369
370 } // namespace OHOS::Ace::NG
371