1 /*
2  * Copyright (c) 2023 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/navigation/navigation_stack.h"
17 
18 #include <utility>
19 
20 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
21 #include "core/components_ng/pattern/navrouter/navrouter_group_node.h"
22 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
23 
24 namespace OHOS::Ace::NG {
25 namespace {
26 constexpr int32_t NOT_EXIST = -1;
27 }
Remove()28 void NavigationStack::Remove()
29 {
30     if (navPathList_.empty()) {
31         return;
32     }
33     navPathList_.pop_back();
34     Pop();
35 }
36 
Remove(const std::string & name)37 void NavigationStack::Remove(const std::string& name)
38 {
39     if (navPathList_.empty()) {
40         return;
41     }
42     for (auto it = navPathList_.begin(); it != navPathList_.end();) {
43         if (((*it).first) == name) {
44             it = navPathList_.erase(it);
45         } else {
46             ++it;
47         }
48     }
49     RemoveName(name);
50 }
51 
Remove(const std::string & name,const RefPtr<UINode> & navDestinationNode)52 void NavigationStack::Remove(const std::string& name, const RefPtr<UINode>& navDestinationNode)
53 {
54     int32_t index = RemoveInNavPathList(name, navDestinationNode);
55     if (index != NOT_EXIST) {
56         RemoveIndex(index);
57     }
58 }
59 
RemoveInNavPathList(const std::string & name,const RefPtr<UINode> & navDestinationNode)60 int32_t NavigationStack::RemoveInNavPathList(const std::string& name, const RefPtr<UINode>& navDestinationNode)
61 {
62     int32_t index = NOT_EXIST;
63     if (!navPathList_.empty()) {
64         index = FindIndex(name, navDestinationNode, true);
65     }
66     if (index != NOT_EXIST) {
67         auto it = navPathList_.begin() + index;
68         navPathList_.erase(it);
69     }
70     return index;
71 }
72 
RemoveInPreNavPathList(const std::string & name,const RefPtr<UINode> & navDestinationNode)73 int32_t NavigationStack::RemoveInPreNavPathList(const std::string& name, const RefPtr<UINode>& navDestinationNode)
74 {
75     int32_t index = NOT_EXIST;
76     if (!preNavPathList_.empty()) {
77         index = FindIndex(name, navDestinationNode, false);
78     }
79     if (index != NOT_EXIST) {
80         auto it = preNavPathList_.begin() + index;
81         preNavPathList_.erase(it);
82     }
83     return index;
84 }
85 
RemoveIndex(int32_t index)86 void NavigationStack::RemoveIndex(int32_t index) {}
87 
Add(const std::string & name,const RefPtr<UINode> & navDestinationNode,NavRouteMode mode,const RefPtr<RouteInfo> & routeInfo)88 void NavigationStack::Add(const std::string& name, const RefPtr<UINode>& navDestinationNode, NavRouteMode mode,
89     const RefPtr<RouteInfo>& routeInfo)
90 {
91     if (mode == NavRouteMode::PUSH) {
92         Add(name, navDestinationNode, routeInfo);
93     } else if (mode == NavRouteMode::PUSH_WITH_RECREATE) {
94         AddForDefault(name, navDestinationNode, routeInfo);
95     } else if (mode == NavRouteMode::REPLACE) {
96         AddForReplace(name, navDestinationNode, routeInfo);
97     }
98 }
99 
100 #if defined(ENABLE_NAV_SPLIT_MODE)
isLastListContains(const std::string & name,const RefPtr<UINode> & navDestinationNode)101 bool NavigationStack::isLastListContains(
102     const std::string& name, const RefPtr<UINode>& navDestinationNode)
103 {
104     if (lastNavPathList_.empty()) {
105         return false;
106     }
107     // find from top to bottom
108     for (auto it = lastNavPathList_.rbegin(); it != lastNavPathList_.rend(); ++it) {
109         if ((*it).first == name && (*it).second == navDestinationNode) {
110             return true;
111         }
112     }
113     return false;
114 }
115 #endif
116 
Add(const std::string & name,const RefPtr<UINode> & navDestinationNode,const RefPtr<RouteInfo> & routeInfo)117 void NavigationStack::Add(
118     const std::string& name, const RefPtr<UINode>& navDestinationNode, const RefPtr<RouteInfo>& routeInfo)
119 {
120     // for the old page: keep the UINode, and keep in the stack
121     auto index = FindIndex(name, navDestinationNode, true);
122     if (index != NOT_EXIST) {
123         RemoveIndex(index);
124         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "This navigation destination node already exists");
125     }
126     navPathList_.emplace_back(std::make_pair(name, navDestinationNode));
127     if (index != NOT_EXIST) {
128         Push(name, index);
129     } else {
130         Push(name, routeInfo);
131     }
132 }
133 
AddForDefault(const std::string & name,const RefPtr<UINode> & navDestinationNode,const RefPtr<RouteInfo> & routeInfo)134 void NavigationStack::AddForDefault(
135     const std::string& name, const RefPtr<UINode>& navDestinationNode, const RefPtr<RouteInfo>& routeInfo)
136 {
137     // for the old page: destroy the UINode, but keep in the stack
138     auto index = FindIndex(name, navDestinationNode, true);
139     if (index != NOT_EXIST) {
140         RemoveIndex(index);
141     }
142     navPathList_.emplace_back(std::make_pair(name, navDestinationNode));
143     // push param into JSNavigationStack
144     if (index != NOT_EXIST) {
145         Push(name, index);
146     } else {
147         Push(name, routeInfo);
148     }
149 }
150 
AddForReplace(const std::string & name,const RefPtr<UINode> & navDestinationNode,const RefPtr<RouteInfo> & routeInfo)151 void NavigationStack::AddForReplace(
152     const std::string& name, const RefPtr<UINode>& navDestinationNode, const RefPtr<RouteInfo>& routeInfo)
153 {
154     // for the old page: destroy the UINode, and move out of the stack
155     if (navPathList_.empty()) {
156         Add(name, navDestinationNode);
157         return;
158     }
159     auto index = FindIndex(name, navDestinationNode, true);
160     if (index != NOT_EXIST) {
161         navPathList_.pop_back(); // move the old page
162         RemoveIndex(index);
163     } else {
164         navPathList_.pop_back();
165     }
166     navPathList_.emplace_back(std::make_pair(name, navDestinationNode));
167 
168     Pop();
169     if (index != NOT_EXIST) {
170         Push(name, index);
171     } else {
172         Push(name, routeInfo);
173     }
174 }
175 
RemoveAll()176 void NavigationStack::RemoveAll()
177 {
178     navPathList_.clear();
179     Clear();
180 }
181 
FindIndex(const std::string & name,const RefPtr<UINode> & navDestinationNode,bool isNavPathList)182 int32_t NavigationStack::FindIndex(
183     const std::string& name, const RefPtr<UINode>& navDestinationNode, bool isNavPathList)
184 {
185     NavPathList navPathList = isNavPathList ? navPathList_ : preNavPathList_;
186     if (navPathList.empty()) {
187         return NOT_EXIST;
188     }
189     int32_t index = static_cast<int32_t>(navPathList.size()) - 1;
190     // find from top to bottom
191     for (auto it = navPathList.rbegin(); it != navPathList.rend(); ++it) {
192         if ((*it).first == name && (*it).second == navDestinationNode) {
193             return index;
194         }
195         --index;
196     }
197     return NOT_EXIST;
198 }
199 
Get()200 RefPtr<UINode> NavigationStack::Get()
201 {
202     if (navPathList_.empty()) {
203         return nullptr;
204     }
205     int32_t top = static_cast<int32_t>(navPathList_.size()) - 1;
206     return navPathList_[top].second;
207 }
208 
Get(const std::string & name,RefPtr<UINode> & navDestinationNode,int32_t & index)209 bool NavigationStack::Get(const std::string& name, RefPtr<UINode>& navDestinationNode, int32_t& index)
210 {
211     // from bottom to top
212     if (navPathList_.empty()) {
213         navDestinationNode = nullptr;
214         index = NOT_EXIST;
215         return false;
216     }
217     int32_t curIndex = 0;
218     for (auto it = navPathList_.begin(); it != navPathList_.end(); ++it) {
219         if ((*it).first == name) {
220             navDestinationNode = (*it).second;
221             index = curIndex;
222             return true;
223         }
224         curIndex++;
225     }
226     navDestinationNode = nullptr;
227     index = NOT_EXIST;
228     return false;
229 }
230 
Get(int32_t index)231 RefPtr<UINode> NavigationStack::Get(int32_t index)
232 {
233     if (index < 0 || index >= Size()) {
234         return nullptr;
235     }
236     return navPathList_[index].second;
237 }
238 
GetNavDesNameByIndex(int32_t index)239 std::string NavigationStack::GetNavDesNameByIndex(int32_t index)
240 {
241     if (index < 0 || index >= Size()) {
242         return "";
243     }
244     return navPathList_[index].first;
245 }
246 
GetFromPreBackup(const std::string & name,RefPtr<UINode> & navDestinationNode,int32_t & index)247 bool NavigationStack::GetFromPreBackup(const std::string& name, RefPtr<UINode>& navDestinationNode, int32_t& index)
248 {
249     // from bottom to top
250     if (preNavPathList_.empty()) {
251         navDestinationNode = nullptr;
252         index = NOT_EXIST;
253         return false;
254     }
255     int32_t curIndex = 0;
256     for (auto it = preNavPathList_.begin(); it != preNavPathList_.end(); ++it) {
257         if ((*it).first == name) {
258             navDestinationNode =  (*it).second;
259             index = curIndex;
260             return true;
261         }
262         curIndex++;
263     }
264     navDestinationNode = nullptr;
265     index = NOT_EXIST;
266     return false;
267 }
268 
GetPre(const std::string & name,const RefPtr<UINode> & navDestinationNode)269 RefPtr<UINode> NavigationStack::GetPre(const std::string& name, const RefPtr<UINode>& navDestinationNode)
270 {
271     if (navPathList_.empty() || navPathList_.size() == 1) {
272         return nullptr;
273     }
274     auto index = FindIndex(name, navDestinationNode, true);
275     if (index == 0 || index == NOT_EXIST) {
276         // no more navDestinationNode in front or no this navDestinationNode
277         return nullptr;
278     } else {
279         --index;
280         return navPathList_[index].second;
281     }
282 }
283 
IsEmpty()284 bool NavigationStack::IsEmpty()
285 {
286     return false;
287 }
288 
Pop()289 void NavigationStack::Pop() {}
290 
GetAllPathName()291 std::vector<std::string> NavigationStack::GetAllPathName()
292 {
293     if (navPathList_.empty()) {
294         return {};
295     }
296     std::vector<std::string> pathNames;
297     for (const auto& path : navPathList_) {
298         pathNames.emplace_back(path.first);
299     }
300     return pathNames;
301 }
302 
GetAllPathIndex()303 std::vector<int32_t> NavigationStack::GetAllPathIndex()
304 {
305     if (navPathList_.empty()) {
306         return {};
307     }
308     std::vector<int32_t> pathIndex;
309     for (int32_t i = 0; i < static_cast<int32_t>(navPathList_.size()); i++) {
310         pathIndex.emplace_back(i);
311     }
312     return pathIndex;
313 }
Push(const std::string & name,const RefPtr<RouteInfo> & routeInfo)314 void NavigationStack::Push(const std::string& name, const RefPtr<RouteInfo>& routeInfo) {}
315 
Push(const std::string & name,int32_t index)316 void NavigationStack::Push(const std::string& name, int32_t index) {}
317 
RemoveName(const std::string & name)318 void NavigationStack::RemoveName(const std::string& name) {}
319 
Clear()320 void NavigationStack::Clear()
321 {
322     navPathList_.clear();
323     cacheNodes_.clear();
324 }
325 
CreateNodeByIndex(int32_t index,const WeakPtr<UINode> & node)326 RefPtr<UINode> NavigationStack::CreateNodeByIndex(int32_t index, const WeakPtr<UINode>& node)
327 {
328     return nullptr;
329 }
330 
CreateNodeByRouteInfo(const RefPtr<RouteInfo> & routeInfo,const WeakPtr<UINode> & node)331 RefPtr<UINode> NavigationStack::CreateNodeByRouteInfo(const RefPtr<RouteInfo>& routeInfo, const WeakPtr<UINode>& node)
332 {
333     return nullptr;
334 }
335 
UpdateReplaceValue(int32_t value) const336 void NavigationStack::UpdateReplaceValue(int32_t value) const {}
337 
GetReplaceValue() const338 int32_t NavigationStack::GetReplaceValue() const
339 {
340     return 0;
341 }
342 
GetAllCacheNodes()343 NavPathList NavigationStack::GetAllCacheNodes()
344 {
345     return cacheNodes_;
346 }
347 
AddCacheNode(const std::string & name,const RefPtr<UINode> & uiNode)348 void NavigationStack::AddCacheNode(
349     const std::string& name, const RefPtr<UINode>& uiNode)
350 {
351     if (name.empty() || uiNode == nullptr) {
352         return;
353     }
354 
355     auto navDestination = AceType::DynamicCast<NG::NavDestinationGroupNode>(
356         NG::NavigationGroupNode::GetNavDestinationNode(uiNode));
357     if (navDestination) {
358         navDestination->SetIsCacheNode(true);
359     }
360 
361     cacheNodes_.emplace_back(std::make_pair(name, uiNode));
362 }
363 
RemoveCacheNode(int32_t handle)364 void NavigationStack::RemoveCacheNode(int32_t handle)
365 {
366     if (handle <= 0) {
367         return;
368     }
369 
370     for (auto it = cacheNodes_.begin(); it != cacheNodes_.end(); ++it) {
371         if ((*it).second->GetId() == handle) {
372             auto navDestination = AceType::DynamicCast<NG::NavDestinationGroupNode>(
373                 NG::NavigationGroupNode::GetNavDestinationNode(it->second));
374             if (navDestination) {
375                 navDestination->SetIsCacheNode(false);
376             }
377             cacheNodes_.erase(it);
378             return;
379         }
380     }
381 }
382 
RemoveCacheNode(NavPathList & cacheNodes,const std::string & name,const RefPtr<UINode> & navDestinationNode)383 void NavigationStack::RemoveCacheNode(
384     NavPathList& cacheNodes, const std::string& name, const RefPtr<UINode>& navDestinationNode)
385 {
386     if (cacheNodes.empty() || name.empty() || navDestinationNode == nullptr) {
387         return;
388     }
389 
390     for (auto it = cacheNodes.begin(); it != cacheNodes.end(); ++it) {
391         if ((*it).first == name || (*it).second == navDestinationNode) {
392             cacheNodes.erase(it);
393             return;
394         }
395     }
396 }
397 
ReOrderCache(const std::string & name,const RefPtr<UINode> & navDestinationNode)398 void NavigationStack::ReOrderCache(const std::string& name, const RefPtr<UINode>& navDestinationNode)
399 {
400     if (name.empty() || navDestinationNode == nullptr) {
401         return;
402     }
403 
404     auto cacheNodes = cacheNodes_;
405     cacheNodes_.clear();
406     cacheNodes_.emplace_back(std::make_pair(name, navDestinationNode));
407     for (auto it = cacheNodes.begin(); it != cacheNodes.end(); ++it) {
408         if ((*it).first == name && (*it).second == navDestinationNode) {
409             continue;
410         }
411 
412         cacheNodes_.emplace_back(std::make_pair((*it).first, (*it).second));
413     }
414 }
415 
GetFromCacheNode(NavPathList & cacheNodes,const std::string & name)416 RefPtr<UINode> NavigationStack::GetFromCacheNode(
417     NavPathList& cacheNodes, const std::string& name)
418 {
419     if (cacheNodes.empty() || name.empty()) {
420         return nullptr;
421     }
422     for (auto it = cacheNodes.begin(); it != cacheNodes.end(); ++it) {
423         if ((*it).first == name) {
424             return (*it).second;
425         }
426     }
427     return nullptr;
428 }
429 
GetFromCacheNode(const std::string & name)430 RefPtr<UINode> NavigationStack::GetFromCacheNode(const std::string& name)
431 {
432     if (name.empty()) {
433         return nullptr;
434     }
435     for (auto it = cacheNodes_.begin(); it != cacheNodes_.end(); ++it) {
436         if ((*it).first == name) {
437             return (*it).second;
438         }
439     }
440     return nullptr;
441 }
442 
GetFromCacheNode(int32_t handle)443 std::optional<std::pair<std::string, RefPtr<UINode>>> NavigationStack::GetFromCacheNode(int32_t handle)
444 {
445     for (auto it = cacheNodes_.begin(); it != cacheNodes_.end(); ++it) {
446         if ((*it).second || (*it).second->GetId() == handle) {
447             return std::make_pair((*it).first, (*it).second);
448         }
449     }
450     return std::nullopt;
451 }
452 
DumpStackInfo() const453 std::vector<std::string> NavigationStack::DumpStackInfo() const
454 {
455     std::vector<std::string> dumpInfos;
456     for (size_t i = 0; i < navPathList_.size(); ++i) {
457         const auto& name = navPathList_[i].first;
458         std::string info = "[" + std::to_string(i) + "]{ name: \"" + name + "\" }";
459         dumpInfos.push_back(std::move(info));
460     }
461     return dumpInfos;
462 }
463 } // namespace OHOS::Ace::NG
464