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
Add(const std::string & name,const RefPtr<UINode> & navDestinationNode,const RefPtr<RouteInfo> & routeInfo)100 void NavigationStack::Add(
101 const std::string& name, const RefPtr<UINode>& navDestinationNode, const RefPtr<RouteInfo>& routeInfo)
102 {
103 // for the old page: keep the UINode, and keep in the stack
104 auto index = FindIndex(name, navDestinationNode, true);
105 if (index != NOT_EXIST) {
106 RemoveIndex(index);
107 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "This navigation destination node already exists");
108 }
109 navPathList_.emplace_back(std::make_pair(name, navDestinationNode));
110 if (index != NOT_EXIST) {
111 Push(name, index);
112 } else {
113 Push(name, routeInfo);
114 }
115 }
116
AddForDefault(const std::string & name,const RefPtr<UINode> & navDestinationNode,const RefPtr<RouteInfo> & routeInfo)117 void NavigationStack::AddForDefault(
118 const std::string& name, const RefPtr<UINode>& navDestinationNode, const RefPtr<RouteInfo>& routeInfo)
119 {
120 // for the old page: destroy the UINode, but keep in the stack
121 auto index = FindIndex(name, navDestinationNode, true);
122 if (index != NOT_EXIST) {
123 RemoveIndex(index);
124 }
125 navPathList_.emplace_back(std::make_pair(name, navDestinationNode));
126 // push param into JSNavigationStack
127 if (index != NOT_EXIST) {
128 Push(name, index);
129 } else {
130 Push(name, routeInfo);
131 }
132 }
133
AddForReplace(const std::string & name,const RefPtr<UINode> & navDestinationNode,const RefPtr<RouteInfo> & routeInfo)134 void NavigationStack::AddForReplace(
135 const std::string& name, const RefPtr<UINode>& navDestinationNode, const RefPtr<RouteInfo>& routeInfo)
136 {
137 // for the old page: destroy the UINode, and move out of the stack
138 if (navPathList_.empty()) {
139 Add(name, navDestinationNode);
140 return;
141 }
142 auto index = FindIndex(name, navDestinationNode, true);
143 if (index != NOT_EXIST) {
144 navPathList_.pop_back(); // move the old page
145 RemoveIndex(index);
146 } else {
147 navPathList_.pop_back();
148 }
149 navPathList_.emplace_back(std::make_pair(name, navDestinationNode));
150
151 Pop();
152 if (index != NOT_EXIST) {
153 Push(name, index);
154 } else {
155 Push(name, routeInfo);
156 }
157 }
158
RemoveAll()159 void NavigationStack::RemoveAll()
160 {
161 navPathList_.clear();
162 Clear();
163 }
164
FindIndex(const std::string & name,const RefPtr<UINode> & navDestinationNode,bool isNavPathList)165 int32_t NavigationStack::FindIndex(
166 const std::string& name, const RefPtr<UINode>& navDestinationNode, bool isNavPathList)
167 {
168 NavPathList navPathList = isNavPathList ? navPathList_ : preNavPathList_;
169 if (navPathList.empty()) {
170 return NOT_EXIST;
171 }
172 int32_t index = static_cast<int32_t>(navPathList.size()) - 1;
173 // find from top to bottom
174 for (auto it = navPathList.rbegin(); it != navPathList.rend(); ++it) {
175 if ((*it).first == name && (*it).second == navDestinationNode) {
176 return index;
177 }
178 --index;
179 }
180 return NOT_EXIST;
181 }
182
Get()183 RefPtr<UINode> NavigationStack::Get()
184 {
185 if (navPathList_.empty()) {
186 return nullptr;
187 }
188 int32_t top = static_cast<int32_t>(navPathList_.size()) - 1;
189 return navPathList_[top].second;
190 }
191
Get(const std::string & name,RefPtr<UINode> & navDestinationNode,int32_t & index)192 bool NavigationStack::Get(const std::string& name, RefPtr<UINode>& navDestinationNode, int32_t& index)
193 {
194 // from bottom to top
195 if (navPathList_.empty()) {
196 navDestinationNode = nullptr;
197 index = NOT_EXIST;
198 return false;
199 }
200 int32_t curIndex = 0;
201 for (auto it = navPathList_.begin(); it != navPathList_.end(); ++it) {
202 if ((*it).first == name) {
203 navDestinationNode = (*it).second;
204 index = curIndex;
205 return true;
206 }
207 curIndex++;
208 }
209 navDestinationNode = nullptr;
210 index = NOT_EXIST;
211 return false;
212 }
213
Get(int32_t index)214 RefPtr<UINode> NavigationStack::Get(int32_t index)
215 {
216 if (index < 0 || index >= Size()) {
217 return nullptr;
218 }
219 return navPathList_[index].second;
220 }
221
GetNavDesNameByIndex(int32_t index)222 std::string NavigationStack::GetNavDesNameByIndex(int32_t index)
223 {
224 if (index < 0 || index >= Size()) {
225 return "";
226 }
227 return navPathList_[index].first;
228 }
229
GetFromPreBackup(const std::string & name,RefPtr<UINode> & navDestinationNode,int32_t & index)230 bool NavigationStack::GetFromPreBackup(const std::string& name, RefPtr<UINode>& navDestinationNode, int32_t& index)
231 {
232 // from bottom to top
233 if (preNavPathList_.empty()) {
234 navDestinationNode = nullptr;
235 index = NOT_EXIST;
236 return false;
237 }
238 int32_t curIndex = 0;
239 for (auto it = preNavPathList_.begin(); it != preNavPathList_.end(); ++it) {
240 if ((*it).first == name) {
241 navDestinationNode = (*it).second;
242 index = curIndex;
243 return true;
244 }
245 curIndex++;
246 }
247 navDestinationNode = nullptr;
248 index = NOT_EXIST;
249 return false;
250 }
251
GetPre(const std::string & name,const RefPtr<UINode> & navDestinationNode)252 RefPtr<UINode> NavigationStack::GetPre(const std::string& name, const RefPtr<UINode>& navDestinationNode)
253 {
254 if (navPathList_.empty() || navPathList_.size() == 1) {
255 return nullptr;
256 }
257 auto index = FindIndex(name, navDestinationNode, true);
258 if (index == 0 || index == NOT_EXIST) {
259 // no more navDestinationNode in front or no this navDestinationNode
260 return nullptr;
261 } else {
262 --index;
263 return navPathList_[index].second;
264 }
265 }
266
IsEmpty()267 bool NavigationStack::IsEmpty()
268 {
269 return false;
270 }
271
Pop()272 void NavigationStack::Pop() {}
273
GetAllPathName()274 std::vector<std::string> NavigationStack::GetAllPathName()
275 {
276 if (navPathList_.empty()) {
277 return {};
278 }
279 std::vector<std::string> pathNames;
280 for (const auto& path : navPathList_) {
281 pathNames.emplace_back(path.first);
282 }
283 return pathNames;
284 }
285
GetAllPathIndex()286 std::vector<int32_t> NavigationStack::GetAllPathIndex()
287 {
288 if (navPathList_.empty()) {
289 return {};
290 }
291 std::vector<int32_t> pathIndex;
292 for (int32_t i = 0; i < static_cast<int32_t>(navPathList_.size()); i++) {
293 pathIndex.emplace_back(i);
294 }
295 return pathIndex;
296 }
Push(const std::string & name,const RefPtr<RouteInfo> & routeInfo)297 void NavigationStack::Push(const std::string& name, const RefPtr<RouteInfo>& routeInfo) {}
298
Push(const std::string & name,int32_t index)299 void NavigationStack::Push(const std::string& name, int32_t index) {}
300
RemoveName(const std::string & name)301 void NavigationStack::RemoveName(const std::string& name) {}
302
Clear()303 void NavigationStack::Clear()
304 {
305 navPathList_.clear();
306 cacheNodes_.clear();
307 }
308
CreateNodeByIndex(int32_t index,const WeakPtr<UINode> & node)309 RefPtr<UINode> NavigationStack::CreateNodeByIndex(int32_t index, const WeakPtr<UINode>& node)
310 {
311 return nullptr;
312 }
313
CreateNodeByRouteInfo(const RefPtr<RouteInfo> & routeInfo,const WeakPtr<UINode> & node)314 RefPtr<UINode> NavigationStack::CreateNodeByRouteInfo(const RefPtr<RouteInfo>& routeInfo, const WeakPtr<UINode>& node)
315 {
316 return nullptr;
317 }
318
UpdateReplaceValue(int32_t value) const319 void NavigationStack::UpdateReplaceValue(int32_t value) const {}
320
GetReplaceValue() const321 int32_t NavigationStack::GetReplaceValue() const
322 {
323 return 0;
324 }
325
GetAllCacheNodes()326 NavPathList NavigationStack::GetAllCacheNodes()
327 {
328 return cacheNodes_;
329 }
330
AddCacheNode(const std::string & name,const RefPtr<UINode> & uiNode)331 void NavigationStack::AddCacheNode(
332 const std::string& name, const RefPtr<UINode>& uiNode)
333 {
334 if (name.empty() || uiNode == nullptr) {
335 return;
336 }
337
338 auto navDestination = AceType::DynamicCast<NG::NavDestinationGroupNode>(
339 NG::NavigationGroupNode::GetNavDestinationNode(uiNode));
340 if (navDestination) {
341 navDestination->SetIsCacheNode(true);
342 }
343
344 cacheNodes_.emplace_back(std::make_pair(name, uiNode));
345 }
346
RemoveCacheNode(int32_t handle)347 void NavigationStack::RemoveCacheNode(int32_t handle)
348 {
349 if (handle <= 0) {
350 return;
351 }
352
353 for (auto it = cacheNodes_.begin(); it != cacheNodes_.end(); ++it) {
354 if ((*it).second->GetId() == handle) {
355 auto navDestination = AceType::DynamicCast<NG::NavDestinationGroupNode>(
356 NG::NavigationGroupNode::GetNavDestinationNode(it->second));
357 if (navDestination) {
358 navDestination->SetIsCacheNode(false);
359 }
360 cacheNodes_.erase(it);
361 return;
362 }
363 }
364 }
365
RemoveCacheNode(NavPathList & cacheNodes,const std::string & name,const RefPtr<UINode> & navDestinationNode)366 void NavigationStack::RemoveCacheNode(
367 NavPathList& cacheNodes, const std::string& name, const RefPtr<UINode>& navDestinationNode)
368 {
369 if (cacheNodes.empty() || name.empty() || navDestinationNode == nullptr) {
370 return;
371 }
372
373 for (auto it = cacheNodes.begin(); it != cacheNodes.end(); ++it) {
374 if ((*it).first == name || (*it).second == navDestinationNode) {
375 cacheNodes.erase(it);
376 return;
377 }
378 }
379 }
380
ReOrderCache(const std::string & name,const RefPtr<UINode> & navDestinationNode)381 void NavigationStack::ReOrderCache(const std::string& name, const RefPtr<UINode>& navDestinationNode)
382 {
383 if (name.empty() || navDestinationNode == nullptr) {
384 return;
385 }
386
387 auto cacheNodes = cacheNodes_;
388 cacheNodes_.clear();
389 cacheNodes_.emplace_back(std::make_pair(name, navDestinationNode));
390 for (auto it = cacheNodes.begin(); it != cacheNodes.end(); ++it) {
391 if ((*it).first == name && (*it).second == navDestinationNode) {
392 continue;
393 }
394
395 cacheNodes_.emplace_back(std::make_pair((*it).first, (*it).second));
396 }
397 }
398
GetFromCacheNode(NavPathList & cacheNodes,const std::string & name)399 RefPtr<UINode> NavigationStack::GetFromCacheNode(
400 NavPathList& cacheNodes, const std::string& name)
401 {
402 if (cacheNodes.empty() || name.empty()) {
403 return nullptr;
404 }
405 for (auto it = cacheNodes.begin(); it != cacheNodes.end(); ++it) {
406 if ((*it).first == name) {
407 return (*it).second;
408 }
409 }
410 return nullptr;
411 }
412
GetFromCacheNode(const std::string & name)413 RefPtr<UINode> NavigationStack::GetFromCacheNode(const std::string& name)
414 {
415 if (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(int32_t handle)426 std::optional<std::pair<std::string, RefPtr<UINode>>> NavigationStack::GetFromCacheNode(int32_t handle)
427 {
428 for (auto it = cacheNodes_.begin(); it != cacheNodes_.end(); ++it) {
429 if ((*it).second || (*it).second->GetId() == handle) {
430 return std::make_pair((*it).first, (*it).second);
431 }
432 }
433 return std::nullopt;
434 }
435
DumpStackInfo() const436 std::vector<std::string> NavigationStack::DumpStackInfo() const
437 {
438 std::vector<std::string> dumpInfos;
439 for (size_t i = 0; i < navPathList_.size(); ++i) {
440 const auto& name = navPathList_[i].first;
441 std::string info = "[" + std::to_string(i) + "]{ name: \"" + name + "\" }";
442 dumpInfos.push_back(std::move(info));
443 }
444 return dumpInfos;
445 }
446 } // namespace OHOS::Ace::NG
447