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