• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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/tab_bar/tab_content_element.h"
17 
18 #include <algorithm>
19 
20 #include "core/components/tab_bar/render_tab_content.h"
21 
22 namespace OHOS::Ace {
23 
TabContentElement(const std::list<RefPtr<Component>> & contents)24 TabContentElement::TabContentElement(const std::list<RefPtr<Component>>& contents)
25 {
26     contents_ = contents;
27 }
28 
CreateRenderNode()29 RefPtr<RenderNode> TabContentElement::CreateRenderNode()
30 {
31     RefPtr<RenderNode> node = ComponentGroupElement::CreateRenderNode();
32     RefPtr<RenderTabContent> tabContent = AceType::DynamicCast<RenderTabContent>(node);
33     if (tabContent) {
34         tabContent->RegisterCallback([weakTabContentElement = AceType::WeakClaim(this)](int32_t index) {
35             auto tabContent = weakTabContentElement.Upgrade();
36             if (tabContent) {
37                 tabContent->ChangeByContent(index);
38             }
39         });
40         tabContent->RegisterRequireCallback([weakTabContentElement = AceType::WeakClaim(this)](int32_t index) {
41             auto tabContent = weakTabContentElement.Upgrade();
42             if (tabContent) {
43                 tabContent->PrepareContent(index);
44             }
45         });
46         tabContent->RegisterIndicatorCallback(
47             [weakTabContentElement = AceType::WeakClaim(this)](double percent, int32_t newIndex, bool needChange) {
48                 auto tabContent = weakTabContentElement.Upgrade();
49                 if (tabContent) {
50                     tabContent->IndicatorByContent(percent, newIndex, needChange);
51                 }
52             }
53         );
54     }
55     return node;
56 }
57 
UpdateLastFocusNode()58 void TabContentElement::UpdateLastFocusNode()
59 {
60     if (IsCurrentFocus()) {
61         auto focusNode = GetCurrentFocusNode();
62         if (!focusNode || !focusNode->IsFocusable()) {
63             LostFocus();
64             itLastFocusNode_ = focusNodes_.end();
65         } else {
66             focusNode->RequestFocusImmediately();
67         }
68     } else {
69         itLastFocusNode_ = focusNodes_.end();
70     }
71 }
72 
IndicatorByContent(double percent,int32_t newIndex,bool needChange)73 void TabContentElement::IndicatorByContent(double percent, int32_t newIndex, bool needChange)
74 {
75     if (controller_) {
76         controller_->SetIndicatorByScrollContent(percent, newIndex, needChange);
77     }
78 }
79 
ChangeByContent(int32_t index)80 void TabContentElement::ChangeByContent(int32_t index)
81 {
82     if (controller_) {
83         controller_->SetIndexByScrollContent(index);
84     }
85     lastIndex_ = index;
86     UpdateLastFocusNode();
87 }
88 
ChangeByBar(int32_t index,bool isFromController)89 void TabContentElement::ChangeByBar(int32_t index, bool isFromController)
90 {
91     LOGD("change content by tab bar index:%{public}d", index);
92     newBarIndex_ = index;
93     fromController_ = isFromController;
94     MarkDirty();
95 }
96 
ChangeDispatch(int32_t index)97 void TabContentElement::ChangeDispatch(int32_t index)
98 {
99     LOGD("change content by tab bar index:%{public}d", index);
100     auto content = AceType::DynamicCast<RenderTabContent>(GetRenderNode());
101     if (content) {
102         content->FireDomChangeEvent(index);
103     }
104 }
105 
PrepareContent(int32_t index)106 void TabContentElement::PrepareContent(int32_t index)
107 {
108     LOGD("request prepareContent new index:%{public}d", index);
109     newIndex_ = index;
110     MarkDirty();
111 }
112 
Update()113 void TabContentElement::Update()
114 {
115     if (NeedUpdate()) {
116         RefPtr<TabContentComponent> tabContent = AceType::DynamicCast<TabContentComponent>(component_);
117         if (!tabContent) {
118             LOGE("Get tabContent failed");
119             return;
120         }
121         contents_ = tabContent->GetChildren();
122         auto controller = tabContent->GetController();
123         if (controller && (controller_ != controller)) {
124             // Get index from old controller before replace.
125             if (!controller->IsIndexDefined() && controller_) {
126                 controller->SetIndexWithoutChangeContent(controller_->GetIndex());
127             }
128             controller_ = controller;
129         }
130         if (!controller_) {
131             LOGE("Get controller failed");
132             return;
133         }
134         controller_->SetContentElement(AceType::Claim(this));
135         if (controller_->GetIndex() >= static_cast<int32_t>(contents_.size())) {
136             controller_->SetIndexWithoutChangeContent(static_cast<int32_t>(contents_.size()) - 1);
137         }
138         controller_->SetTotalCount(static_cast<int32_t>(contents_.size()));
139         newComponentBuild_ = true;
140     }
141     ComponentGroupElement::Update();
142 }
143 
PerformBuild()144 void TabContentElement::PerformBuild()
145 {
146     if (contents_.empty()) {
147         LOGD("contents is empty");
148         ComponentGroupElement::PerformBuild();
149         return;
150     }
151     RefPtr<RenderTabContent> tabContent = AceType::DynamicCast<RenderTabContent>(renderNode_);
152     if (!tabContent || !controller_ || !renderNode_) {
153         LOGW("tabContent or controller is null.");
154         return;
155     }
156 
157     auto it = contents_.begin();
158     // if have new content requested by drag, build the new child, else build current child
159     int32_t target = newIndex_ >= 0 ? newIndex_ : controller_->GetIndex();
160     LOGD("TabContentElement::PerformBuild: target: %{public}d", target);
161     std::advance(it, target);
162     if (it == contents_.end()) {
163         LOGE("no content at index %{public}d.", target);
164         return;
165     }
166     auto childIter = childMap_.find(target);
167     if (childIter == childMap_.end()) {
168         auto newChild = UpdateChild(nullptr, *it);
169         focusIndexMap_.emplace(target);
170         childMap_.emplace(target, newChild);
171         auto renderChild = newChild->GetRenderNode();
172         if (renderChild) {
173             tabContent->AddChildContent(target, renderChild);
174         }
175         renderNode_->MarkNeedLayout();
176     } else if (NeedUpdate()) {
177         UpdateChild(childIter->second, *it);
178     }
179 
180     // process for new content requested by drag
181     if (target == newIndex_) {
182         tabContent->UpdateDragPosition(newIndex_);
183         newIndex_ = -1;
184     }
185     // process for new content requested by tab bar
186     if (target == newBarIndex_) {
187         tabContent->ChangeScroll(newBarIndex_, fromController_);
188         UpdateLastFocusNode();
189         newBarIndex_ = -1;
190     }
191     lastIndex_ = target;
192     fromController_ = false;
193 }
194 
OnFocus()195 void TabContentElement::OnFocus()
196 {
197     // invoke callback
198     FocusNode::OnFocus();
199 
200     auto focusNode = GetCurrentFocusNode();
201     if (!focusNode) {
202         LOGE("GetCurrentFocusNode failed");
203         return;
204     }
205 
206     if (focusNode->RequestFocusImmediately()) {
207         itLastFocusNode_ = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
208     } else {
209         LOGE("RequestFocusImmediately failed");
210     }
211 }
212 
RequestNextFocus(bool vertical,bool reverse,const Rect & rect)213 bool TabContentElement::RequestNextFocus(bool vertical, bool reverse, const Rect& rect)
214 {
215     return false;
216 }
217 
IsFocusable() const218 bool TabContentElement::IsFocusable() const
219 {
220     auto focusNode = GetCurrentFocusNode();
221     if (focusNode) {
222         return focusNode->IsFocusable();
223     }
224     return false;
225 }
226 
GetCurrentFocusNode() const227 RefPtr<FocusNode> TabContentElement::GetCurrentFocusNode() const
228 {
229     if (!controller_) {
230         LOGE("controller is nullptr");
231         return nullptr;
232     }
233 
234     auto childIter = focusChildMap_.find(controller_->GetIndex());
235     if (childIter == focusChildMap_.end()) {
236         return nullptr;
237     }
238     return childIter->second;
239 }
240 
GetTabContentChild(int32_t index) const241 RefPtr<Element> TabContentElement::GetTabContentChild(int32_t index) const
242 {
243     auto childIter = childMap_.find(index);
244     if (childIter == childMap_.end()) {
245         return nullptr;
246     }
247     return childIter->second;
248 }
249 
250 } // namespace OHOS::Ace