• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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/tabs/tabs_pattern.h"
17 #include "core/components_ng/pattern/swiper/swiper_pattern.h"
18 
19 #include "base/geometry/axis.h"
20 #include "base/geometry/dimension.h"
21 #include "base/utils/utils.h"
22 #include "core/components/common/layout/constants.h"
23 #include "core/components/tab_bar/tabs_event.h"
24 #include "core/components_ng/pattern/swiper/swiper_event_hub.h"
25 #include "core/components_ng/pattern/tabs/tab_bar_layout_property.h"
26 #include "core/components_ng/pattern/tabs/tab_bar_paint_property.h"
27 #include "core/components_ng/pattern/tabs/tab_bar_pattern.h"
28 #include "core/components_ng/pattern/tabs/tabs_node.h"
29 #include "core/components_ng/property/property.h"
30 #include "core/components_ng/pattern/divider/divider_layout_property.h"
31 #include "core/components_ng/pattern/divider/divider_render_property.h"
32 #include "core/components_v2/inspector/inspector_constants.h"
33 #include "core/pipeline_ng/pipeline_context.h"
34 
35 namespace OHOS::Ace::NG {
36 namespace {
37 constexpr int32_t CHILDREN_MIN_SIZE = 2;
38 } // namespace
39 
OnAttachToFrameNode()40 void TabsPattern::OnAttachToFrameNode()
41 {
42     auto host = GetHost();
43     CHECK_NULL_VOID(host);
44     host->GetRenderContext()->SetClipToFrame(true);
45 }
46 
SetOnChangeEvent(std::function<void (const BaseEventInfo *)> && event)47 void TabsPattern::SetOnChangeEvent(std::function<void(const BaseEventInfo*)>&& event)
48 {
49     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
50     CHECK_NULL_VOID(tabsNode);
51     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
52     CHECK_NULL_VOID(tabBarNode);
53     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
54     CHECK_NULL_VOID(tabBarPattern);
55     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
56     CHECK_NULL_VOID(swiperNode);
57 
58     ChangeEvent changeEvent([tabBarNode, tabBarPattern, jsEvent = std::move(event)](int32_t index) {
59         auto tabsNode = AceType::DynamicCast<TabsNode>(tabBarNode->GetParent());
60         CHECK_NULL_VOID(tabsNode);
61         auto tabsLayoutProperty = tabsNode->GetLayoutProperty<TabsLayoutProperty>();
62         CHECK_NULL_VOID(tabsLayoutProperty);
63         tabsLayoutProperty->UpdateIndex(index);
64         tabBarPattern->SetIsAnimating(false);
65         auto tabBarLayoutProperty = tabBarPattern->GetLayoutProperty<TabBarLayoutProperty>();
66         CHECK_NULL_VOID(tabBarLayoutProperty);
67         if (!tabBarPattern->IsMaskAnimationByCreate()) {
68             tabBarPattern->HandleBottomTabBarChange(index);
69         }
70         tabBarPattern->SetMaskAnimationByCreate(false);
71         if (tabBarLayoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::FIXED) {
72             tabBarPattern->SetIndicator(index);
73         }
74         tabBarPattern->UpdateIndicator(index);
75         tabBarPattern->UpdateTextColor(index);
76         if (tabBarLayoutProperty->GetTabBarMode().value_or(TabBarMode::FIXED) == TabBarMode::SCROLLABLE) {
77             if (tabBarPattern->GetTabBarStyle() == TabBarStyle::SUBTABBATSTYLE &&
78                 tabBarLayoutProperty->GetAxisValue(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
79                 if (!tabBarPattern->GetChangeByClick()) {
80                     tabBarPattern->PlayTabBarTranslateAnimation(index);
81                     tabBarNode->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
82                 } else {
83                     tabBarPattern->SetChangeByClick(false);
84                 }
85             } else {
86                 tabBarNode->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
87             }
88         }
89         /* js callback */
90         if (jsEvent) {
91             TabContentChangeEvent eventInfo(index);
92             jsEvent(&eventInfo);
93         }
94     });
95 
96     if (onChangeEvent_) {
97         (*onChangeEvent_).swap(changeEvent);
98     } else {
99         onChangeEvent_ = std::make_shared<ChangeEvent>(changeEvent);
100         auto eventHub = swiperNode->GetEventHub<SwiperEventHub>();
101         CHECK_NULL_VOID(eventHub);
102         eventHub->AddOnChangeEvent(onChangeEvent_);
103     }
104 }
105 
SetOnTabBarClickEvent(std::function<void (const BaseEventInfo *)> && event)106 void TabsPattern::SetOnTabBarClickEvent(std::function<void(const BaseEventInfo*)>&& event)
107 {
108     ChangeEvent tabBarClickEvent([jsEvent = std::move(event)](int32_t index) {
109         /* js callback */
110         if (jsEvent) {
111             TabContentChangeEvent eventInfo(index);
112             jsEvent(&eventInfo);
113         }
114     });
115 
116     if (onTabBarClickEvent_) {
117         (*onTabBarClickEvent_).swap(tabBarClickEvent);
118     } else {
119         onTabBarClickEvent_ = std::make_shared<ChangeEvent>(tabBarClickEvent);
120     }
121 }
122 
OnUpdateShowDivider()123 void TabsPattern::OnUpdateShowDivider()
124 {
125     auto host = AceType::DynamicCast<TabsNode>(GetHost());
126     CHECK_NULL_VOID(host);
127     auto layoutProperty = host->GetLayoutProperty<TabsLayoutProperty>();
128     TabsItemDivider defaultDivider;
129     auto divider = layoutProperty->GetDivider().value_or(defaultDivider);
130     auto children = host->GetChildren();
131     if (children.size() < CHILDREN_MIN_SIZE) {
132         LOGE("OnUpdateShowDivider: children is empty or children's size is less than 2.");
133         return;
134     }
135 
136     auto dividerFrameNode = AceType::DynamicCast<FrameNode>(host->GetDivider());
137     CHECK_NULL_VOID(dividerFrameNode);
138     auto dividerRenderProperty = dividerFrameNode->GetPaintProperty<DividerRenderProperty>();
139     CHECK_NULL_VOID(dividerRenderProperty);
140     dividerRenderProperty->UpdateDividerColor(divider.color);
141 
142     auto dividerLayoutProperty = dividerFrameNode->GetLayoutProperty<DividerLayoutProperty>();
143     CHECK_NULL_VOID(dividerLayoutProperty);
144     dividerLayoutProperty->UpdateStrokeWidth(divider.strokeWidth);
145     dividerFrameNode->MarkModifyDone();
146 }
147 
OnModifyDone()148 void TabsPattern::OnModifyDone()
149 {
150     Pattern::OnModifyDone();
151     if (onChangeEvent_) {
152         return;
153     }
154     SetOnChangeEvent(nullptr);
155     OnUpdateShowDivider();
156 }
157 
SetOnIndexChangeEvent(std::function<void (const BaseEventInfo *)> && event)158 void TabsPattern::SetOnIndexChangeEvent(std::function<void(const BaseEventInfo*)>&& event)
159 {
160     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
161     CHECK_NULL_VOID(tabsNode);
162     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
163     CHECK_NULL_VOID(swiperNode);
164 
165     ChangeEvent changeEvent([jsEvent = std::move(event)](int32_t index) {
166         /* js callback */
167         if (jsEvent) {
168             TabContentChangeEvent eventInfo(index);
169             jsEvent(&eventInfo);
170         }
171     });
172 
173     if (onIndexChangeEvent_) {
174         (*onIndexChangeEvent_).swap(changeEvent);
175     } else {
176         onIndexChangeEvent_ = std::make_shared<ChangeEvent>(changeEvent);
177         auto eventHub = swiperNode->GetEventHub<SwiperEventHub>();
178         CHECK_NULL_VOID(eventHub);
179         eventHub->AddOnChangeEvent(onIndexChangeEvent_);
180     }
181 }
182 
ProvideRestoreInfo()183 std::string TabsPattern::ProvideRestoreInfo()
184 {
185     auto jsonObj = JsonUtil::Create(true);
186     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
187     CHECK_NULL_RETURN(tabsNode, "");
188     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
189     CHECK_NULL_RETURN(tabBarNode, "");
190     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
191     CHECK_NULL_RETURN(tabBarPattern, "");
192     return tabBarPattern->ProvideRestoreInfo();
193 }
194 
OnRestoreInfo(const std::string & restoreInfo)195 void TabsPattern::OnRestoreInfo(const std::string& restoreInfo)
196 {
197     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
198     CHECK_NULL_VOID(tabsNode);
199     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
200     CHECK_NULL_VOID(tabBarNode);
201     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
202     CHECK_NULL_VOID(tabBarPattern);
203     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
204     CHECK_NULL_VOID(swiperNode);
205     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
206     CHECK_NULL_VOID(swiperPattern);
207     auto swiperLayoutProperty = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
208     CHECK_NULL_VOID(swiperLayoutProperty);
209     auto info = JsonUtil::ParseJsonString(restoreInfo);
210     if (!info->IsValid() || !info->IsObject()) {
211         LOGW("TabsPattern:: restore info is invalid");
212         return;
213     }
214     auto jsonIsOn = info->GetValue("Index");
215     swiperLayoutProperty->UpdateIndex(jsonIsOn->GetInt());
216 
217     swiperPattern->OnRestoreInfo(restoreInfo);
218     tabBarPattern->OnRestoreInfo(restoreInfo);
219 }
220 
GetScopeFocusAlgorithm()221 ScopeFocusAlgorithm TabsPattern::GetScopeFocusAlgorithm()
222 {
223     auto property = GetLayoutProperty<TabsLayoutProperty>();
224     CHECK_NULL_RETURN(property, {});
225     bool isVertical = true;
226     if (property->GetAxis().has_value()) {
227         isVertical = property->GetAxis().value() == Axis::HORIZONTAL;
228     }
229     return ScopeFocusAlgorithm(isVertical, true, ScopeType::OTHERS,
230         [wp = WeakClaim(this)](
231             FocusStep step, const WeakPtr<FocusHub>& currFocusNode, WeakPtr<FocusHub>& nextFocusNode) {
232             auto tabs = wp.Upgrade();
233             if (tabs) {
234                 nextFocusNode = tabs->GetNextFocusNode(step, currFocusNode);
235             }
236         });
237 }
238 
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)239 WeakPtr<FocusHub> TabsPattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
240 {
241     auto curFocusNode = currentFocusNode.Upgrade();
242     CHECK_NULL_RETURN(curFocusNode, nullptr);
243 
244     auto property = GetLayoutProperty<TabsLayoutProperty>();
245     CHECK_NULL_RETURN(property, nullptr);
246     auto axis = property->GetAxis().value_or(Axis::HORIZONTAL);
247     auto tabBarPosition = property->GetTabBarPosition().value_or(BarPosition::START);
248 
249     auto tabsNode = AceType::DynamicCast<TabsNode>(GetHost());
250     CHECK_NULL_RETURN(tabsNode, nullptr);
251     auto tabBarNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabBar());
252     CHECK_NULL_RETURN(tabBarNode, nullptr);
253     auto tabBarFocusNode = tabBarNode->GetFocusHub();
254     CHECK_NULL_RETURN(tabBarFocusNode, nullptr);
255     auto swiperNode = AceType::DynamicCast<FrameNode>(tabsNode->GetTabs());
256     CHECK_NULL_RETURN(swiperNode, nullptr);
257     auto swiperFocusNode = swiperNode->GetFocusHub();
258     CHECK_NULL_RETURN(swiperFocusNode, nullptr);
259 
260     auto tabBarPattern = tabBarNode->GetPattern<TabBarPattern>();
261     CHECK_NULL_RETURN(tabBarPattern, nullptr);
262     tabBarPattern->SetFirstFocus(true);
263 
264     if (curFocusNode->GetFrameName() == V2::TAB_BAR_ETS_TAG &&
265         ((tabBarPosition == BarPosition::START && axis == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
266         (tabBarPosition == BarPosition::START && axis == Axis::VERTICAL && step == FocusStep::RIGHT) ||
267         (tabBarPosition == BarPosition::END && axis == Axis::HORIZONTAL && step == FocusStep::UP) ||
268         (tabBarPosition == BarPosition::END && axis == Axis::VERTICAL && step == FocusStep::LEFT))) {
269         return AceType::WeakClaim(AceType::RawPtr(swiperFocusNode));
270     }
271     if (curFocusNode->GetFrameName() == V2::SWIPER_ETS_TAG) {
272         if ((tabBarPosition == BarPosition::START && axis == Axis::HORIZONTAL && step == FocusStep::UP) ||
273             (tabBarPosition == BarPosition::START && axis == Axis::VERTICAL && step == FocusStep::LEFT) ||
274             (tabBarPosition == BarPosition::END && axis == Axis::HORIZONTAL && step == FocusStep::DOWN) ||
275             (tabBarPosition == BarPosition::END && axis == Axis::VERTICAL && step == FocusStep::RIGHT)) {
276             return AceType::WeakClaim(AceType::RawPtr(tabBarFocusNode));
277         }
278         if (step == FocusStep::LEFT_END || step == FocusStep::RIGHT_END || step == FocusStep::UP_END ||
279             step == FocusStep::DOWN_END) {
280             return AceType::WeakClaim(AceType::RawPtr(swiperFocusNode));
281         }
282     }
283     return nullptr;
284 }
285 } // namespace OHOS::Ace::NG
286