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