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