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 "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
19 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
20 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
21 
22 namespace OHOS::Ace::NG {
GetOrCreateGroupNode(const std::string & tag,int32_t nodeId,const std::function<RefPtr<Pattern> (void)> & patternCreator)23 RefPtr<NavRouterGroupNode> NavRouterGroupNode::GetOrCreateGroupNode(
24     const std::string& tag, int32_t nodeId, const std::function<RefPtr<Pattern>(void)>& patternCreator)
25 {
26     auto frameNode = GetFrameNode(tag, nodeId);
27     CHECK_NULL_RETURN(!frameNode, AceType::DynamicCast<NavRouterGroupNode>(frameNode));
28     auto pattern = patternCreator ? patternCreator() : MakeRefPtr<Pattern>();
29     auto navRouterGroupNode = AceType::MakeRefPtr<NavRouterGroupNode>(tag, nodeId, pattern);
30     navRouterGroupNode->InitializePatternAndContext();
31     ElementRegister::GetInstance()->AddUINode(navRouterGroupNode);
32     return navRouterGroupNode;
33 }
34 
AddChildToGroup(const RefPtr<UINode> & child,int32_t slot)35 void NavRouterGroupNode::AddChildToGroup(const RefPtr<UINode>& child, int32_t slot)
36 {
37     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(child);
38     if (navDestination) {
39         SetNavDestinationNode(navDestination);
40         auto navDestinationNode = AceType::DynamicCast<FrameNode>(child);
41         CHECK_NULL_VOID(navDestinationNode);
42         auto navDestinationEventHub =
43             AceType::DynamicCast<NavDestinationEventHub>(navDestinationNode->GetEventHub<EventHub>());
44         CHECK_NULL_VOID(navDestinationEventHub);
45         auto eventHub = GetEventHub<NavRouterEventHub>();
46         CHECK_NULL_VOID(eventHub);
47         navDestinationEventHub->SetOnStateChange(eventHub->GetOnStateChange());
48         return;
49     }
50     UINode::AddChild(child);
51 }
52 
DeleteChildFromGroup(int32_t slot)53 void NavRouterGroupNode::DeleteChildFromGroup(int32_t slot)
54 {
55     UINode::RemoveChildAtIndex(slot);
56 }
57 
OnDetachFromMainTree(bool recursive,PipelineContext * context)58 void NavRouterGroupNode::OnDetachFromMainTree(bool recursive, PipelineContext* context)
59 {
60     // remove node in navigation
61     do {
62         if (!navDestinationNode_) {
63             break;
64         }
65         auto navigationNode = weakNavigation_.Upgrade();
66         if (!navigationNode) {
67             break;
68         }
69         auto navigationPattern = AceType::DynamicCast<NavigationPattern>(navigationNode->GetPattern());
70         auto stack = navigationPattern->GetNavigationStack();
71         if (!stack) {
72             break;
73         }
74         auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(
75             DynamicCast<NavDestinationGroupNode>(navDestinationNode_)->GetPattern());
76         stack->Remove(navDestinationPattern->GetName(), navDestinationNode_);
77     } while (false);
78     FrameNode::OnDetachFromMainTree(recursive, context);
79 }
80 
OnAttachToMainTree(bool recursive)81 void NavRouterGroupNode::OnAttachToMainTree(bool recursive)
82 {
83     if (!UseOffscreenProcess()) {
84         ProcessDestinationChangeEvent();
85     }
86     FrameNode::OnAttachToMainTree(recursive);
87 }
88 
OnOffscreenProcess(bool recursive)89 void NavRouterGroupNode::OnOffscreenProcess(bool recursive)
90 {
91     ProcessDestinationChangeEvent();
92     FrameNode::OnOffscreenProcess(recursive);
93 }
94 
ProcessDestinationChangeEvent()95 void NavRouterGroupNode::ProcessDestinationChangeEvent()
96 {
97     auto parent = GetParent();
98     while (parent) {
99         auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(parent);
100         if (navigationNode) {
101             weakNavigation_ = WeakPtr<NavigationGroupNode>(navigationNode);
102             break;
103         }
104         parent = parent->GetParent();
105     }
106     auto onDestinationChange = [weak = WeakClaim(this)]() {
107         auto navRouter = weak.Upgrade();
108         CHECK_NULL_VOID(navRouter);
109         navRouter->AddNavDestinationToNavigation();
110     };
111     auto eventHub = GetEventHub<NavRouterEventHub>();
112     CHECK_NULL_VOID(eventHub);
113     eventHub->SetOnDestinationChange(std::move(onDestinationChange));
114 }
115 
AddNavDestinationToNavigation()116 void NavRouterGroupNode::AddNavDestinationToNavigation()
117 {
118     auto navigationNode = weakNavigation_.Upgrade();
119     CHECK_NULL_VOID(navigationNode);
120     auto navigationPattern = navigationNode->GetPattern<NavigationPattern>();
121     CHECK_NULL_VOID(navigationPattern);
122     // get the navDestination under NavRouter
123     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode());
124     auto currentNavDestination =
125         AceType::DynamicCast<NavDestinationGroupNode>(navigationPattern->GetNavDestinationNode());
126     // do nothing if this navDestination is already at the top
127     if (navDestination && currentNavDestination == navDestination) {
128         return;
129     }
130     // deal with split mode without user provided navigation stack
131     if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT &&
132         !navigationPattern->GetNavigationStackProvided()) {
133         navigationPattern->CleanStack();
134         navigationPattern->UpdateAnimatedValue(false);
135     } else {
136         navigationPattern->UpdateAnimatedValue(true);
137     }
138 
139     auto navRouterPattern = GetPattern<NavRouterPattern>();
140     CHECK_NULL_VOID(navRouterPattern);
141     auto navigationStack = navigationPattern->GetNavigationStack();
142     auto routeInfo = navRouterPattern->GetRouteInfo();
143     std::string name;
144     auto navRouteMode = navRouterPattern->GetNavRouteMode();
145     if (routeInfo) {
146         // create navDestination with routeInfo
147         name = routeInfo->GetName();
148         RefPtr<UINode> uiNode = navigationStack->GetFromCacheNode(name);
149         if (uiNode == nullptr) {
150             uiNode = navigationStack->CreateNodeByRouteInfo(routeInfo, navigationPattern->GetParentCustomNode());
151         }
152 
153         navigationPattern->AddNavDestinationNode(name, uiNode, navRouteMode, routeInfo);
154         auto navRouterEventHub = GetEventHub<NavRouterEventHub>();
155         CHECK_NULL_VOID(navRouterEventHub);
156         if (uiNode) {
157             navigationPattern->AddOnStateChangeItem(uiNode->GetId(), navRouterEventHub->GetOnStateChange());
158         }
159         navDestination = AceType::DynamicCast<NavDestinationGroupNode>(
160             NavigationGroupNode::GetNavDestinationNode(uiNode));
161     } else if (navDestination) {
162         auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
163         CHECK_NULL_VOID(navDestinationPattern);
164         navDestination->SetFromNavrouterAndNoRouteInfo(true);
165         auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
166         if (shallowBuilder && navRouteMode != NavRouteMode::PUSH) {
167             shallowBuilder->MarkIsExecuteDeepRenderDone(false);
168         }
169         auto destinationContent = navDestination->GetContentNode();
170         if (destinationContent && navRouteMode != NavRouteMode::PUSH) {
171             destinationContent->Clean();
172         }
173         WeakPtr<NavigationStack> stack = navigationPattern->GetNavigationStack();
174         navDestinationPattern->SetNavigationStack(stack);
175         name = navDestinationPattern->GetName();
176         navigationPattern->AddNavDestinationNode(name, navDestination, navRouteMode);
177     }
178     if (navDestination) {
179         auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
180         navDestinationPattern->SetNavigationId(navigationNode->GetInspectorId().value_or(""));
181     }
182 
183     // when js navigationStack is provided, modifyDone will be called by state manager.
184     if (!navigationPattern->GetNavigationStackProvided()) {
185         navigationNode->MarkModifyDone();
186         navigationNode->MarkDirtyNode();
187     }
188 }
189 } // namespace OHOS::Ace::NG
190