• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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
16import { Log } from '../utils/Log';
17import { TabItem, TabItemWithText } from '../model/common/TabItem';
18import { BroadCastManager } from '../model/common/BroadCastManager';
19import { BroadCast } from '../utils/BroadCast';
20import { BroadCastConstants } from '../model/common/BroadCastConstants';
21import { Constants } from '../model/common/Constants';
22import { BigDataConstants, ReportToBigDataUtil } from '../utils/ReportToBigDataUtil';
23
24const TAG: string = 'common_TabBar';
25
26export enum DEVICE_TYPE {
27  PHONE_LIKE,
28  PC_LIKE
29}
30
31const TabMap = {
32  0: BigDataConstants.PHOTO_TAB,
33  1: BigDataConstants.ALBUM_TAB,
34}
35
36@Component
37export struct TabBar {
38  @Consume isSelectedMode: boolean;
39  @Consume isAlbumSetSelectedMode: boolean;
40  @Consume isShowSideBar: boolean;
41  @Link @Watch('updateCurrentIndex') currentIndex: number;
42  @Link isSidebar: boolean;
43  @StorageLink('sideBarBoundaryLineOpacity') sideBarBoundaryLineOpacity: number = 1;
44  @StorageLink('sideBarOpacity') sideBarOpacity: number = 1;
45  private tabs: TabItem[] = [];
46  private controller: TabsController;
47  private appBroadCast: BroadCast = BroadCastManager.getInstance().getBroadCast();
48  private deviceType: DEVICE_TYPE = DEVICE_TYPE.PC_LIKE;
49
50  aboutToAppear(): void {
51    this.onTabSelected = this.onTabSelected.bind(this);
52    this.tabs[this.currentIndex].isSelected = true;
53    this.tabs.forEach((tab: TabItem) => {
54      Log.info(TAG, `${JSON.stringify(tab.name)} , ${tab.iconSelected}`)
55    });
56  }
57
58  updateCurrentIndex() {
59    this.onTabSelected(this.currentIndex);
60  }
61
62  build() {
63    if (this.isSidebar) {
64      if (this.deviceType == DEVICE_TYPE.PC_LIKE) {
65        Row() {
66          Flex({
67            direction: FlexDirection.Column,
68            alignItems: ItemAlign.Start,
69            justifyContent: FlexAlign.Start
70          }) {
71            ForEach(this.tabs, (tab: TabItem) => {
72              Tab({
73                tabItem: tab,
74                index: this.tabs.indexOf(tab),
75                onTabSelected: this.onTabSelected,
76                isSidebar: $isSidebar,
77                deviceType: this.deviceType
78              })
79            }, tab => tab.name.id)
80          }
81          .padding({ left: Constants.NUMBER_16, top: Constants.NUMBER_96, right: Constants.NUMBER_16 })
82          .flexGrow(Constants.NUMBER_1)
83          .backgroundColor($r('app.color.default_background_color'))
84
85          // Sidebar boundary line
86          if (this.isShowSideBar) {
87            Row() {
88            }
89            .width(Constants.NUMBER_0)
90            .height(Constants.PERCENT_100)
91            .border({ width: Constants.NUMBER_0_5, color: $r('app.color.album_cover_gradient_start_color') })
92            .opacity(this.sideBarBoundaryLineOpacity)
93          }
94        }
95      } else {
96        Flex({
97          direction: FlexDirection.Column,
98          alignItems: ItemAlign.Center,
99          justifyContent: FlexAlign.Center
100        }) {
101          Column() {
102            ForEach(this.tabs, (tab: TabItem) => {
103              Stack() {
104                Tab({
105                  tabItem: tab,
106                  index: this.tabs.indexOf(tab),
107                  onTabSelected: this.onTabSelected,
108                  isSidebar: $isSidebar,
109                  deviceType: this.deviceType
110                })
111              }
112              .layoutWeight(Constants.NUMBER_1)
113            }, tab => tab.name.id)
114          }
115          .height($r('app.float.horizontal_width'))
116        }
117        .width($r('app.float.tab_bar_width'))
118        .backgroundColor($r('app.color.default_background_color'))
119      }
120
121    } else {
122      Flex({
123        direction: FlexDirection.Row,
124        alignItems: ItemAlign.Center,
125        justifyContent: FlexAlign.Center
126      }) {
127        ForEach(this.tabs, (tab: TabItem) => {
128          Stack() {
129            TabPhone({ tabItem: tab, index: this.tabs.indexOf(tab), onTabSelected: this.onTabSelected })
130          }
131          .layoutWeight(1)
132          .onClick(() => {
133            this.onTabSelected && this.onTabSelected(this.tabs.indexOf(tab));
134            tab.isSelected = true;
135          })
136        }, tab => tab.name.id)
137      }
138      .visibility((this.isSelectedMode || this.isAlbumSetSelectedMode) ? Visibility.None : Visibility.Visible)
139      .height($r('app.float.tab_bar_vertical_height'))
140      .backgroundColor($r('app.color.default_background_color'))
141      .padding({ left: $r('app.float.max_padding_start'), right: $r('app.float.max_padding_end') })
142    }
143  }
144
145  private onTabSelected(index: number): void {
146    Log.debug(TAG, `this.currentIndex: ${this.currentIndex} index: ${index}`);
147    if (this.currentIndex == index) {
148      Log.error(TAG, `it is same: ${index}`);
149      this.appBroadCast.emit(BroadCastConstants.RESET_ZERO, [index]);
150    }
151    this.currentIndex = index;
152    this.controller.changeIndex(this.currentIndex);
153    this.tabs.forEach((tab: TabItem) => {
154      if (this.tabs.indexOf(tab) == index) {
155        tab.isSelected = true;
156      } else {
157        tab.isSelected = false;
158      }
159    })
160    let currentTab = TabMap[this.currentIndex] ? TabMap[this.currentIndex] : BigDataConstants.PHOTO_TAB;
161    let msg = {
162      'SwitchTab': BigDataConstants.CLICK_SWITCH,
163      'Current': currentTab,
164    }
165    ReportToBigDataUtil.report(BigDataConstants.TAB_SWITCH_ID, msg);
166    Log.info(TAG, `select ${this.currentIndex}`);
167  }
168}
169
170// single tab
171@Component
172struct Tab {
173  @ObjectLink tabItem: TabItem;
174  @Link isSidebar: boolean;
175  index: number;
176  onTabSelected: Function;
177  private deviceType: number;
178
179  build() {
180    if (this.deviceType == DEVICE_TYPE.PC_LIKE) {
181      Flex({
182        direction: FlexDirection.Row,
183        alignItems: ItemAlign.Center,
184        justifyContent: FlexAlign.Start
185      }) {
186        Stack() {
187          Image(this.tabItem.getIcon(this.tabItem.isSelected))
188            .height($r('app.float.icon_size'))
189            .width($r('app.float.icon_size'))
190            .objectFit(ImageFit.Fill)
191        }
192        .padding({
193          left: $r('app.float.tab_bar_text_padding_left'),
194        })
195
196        Text(this.tabItem.name)
197          .fontSize($r('sys.float.ohos_id_text_size_sub_title2'))
198          .fontWeight(FontWeight.Medium)
199          .fontColor(this.tabItem.getTextColor())
200          .padding({
201            left: $r('app.float.tab_bar_text_padding_left'),
202            top: $r('app.float.tab_bar_text_padding_horizontal'),
203            bottom: $r('app.float.tab_bar_text_padding_horizontal')
204          })
205          .height($r('app.float.menu_height'))
206      }
207      .backgroundColor(this.tabItem.isSelected ? '#DAE2F5' : $r('app.color.transparent'))
208      .borderRadius($r('app.float.single_tab_margin'))
209      .onClick(() => {
210        this.onTabSelected && this.onTabSelected(this.index);
211        this.tabItem.isSelected = true;
212      })
213    } else {
214      Flex({
215        direction: FlexDirection.Column,
216        alignItems: ItemAlign.Center,
217        justifyContent: FlexAlign.Center,
218      }) {
219        Stack() {
220          Image(this.tabItem.getIcon(this.tabItem.isSelected))
221            .height($r('app.float.icon_size'))
222            .width($r('app.float.icon_size'))
223            .objectFit(ImageFit.Fill)
224        }
225        .padding({
226          left: this.isSidebar ? Constants.NUMBER_0 : $r('app.float.tab_bar_text_padding_left'),
227        })
228
229        Text(this.tabItem.name)
230          .fontSize($r('sys.float.ohos_id_text_size_caption1'))
231          .fontFamily($r('app.string.id_text_font_family_medium'))
232          .fontColor(this.tabItem.getTextColor())
233          .padding({
234            left: $r('app.float.tab_bar_text_padding_horizontal'),
235            top: $r('app.float.tab_bar_text_padding_top'),
236            right: $r('app.float.tab_bar_text_padding_horizontal')
237          })
238      }
239      .onClick(() => {
240        this.onTabSelected && this.onTabSelected(this.index);
241        this.tabItem.isSelected = true;
242      })
243    }
244  }
245}
246
247// phone bottom tab
248@Component
249struct TabPhone {
250  @ObjectLink tabItem: TabItem;
251  index: number;
252  onTabSelected: Function;
253
254  build() {
255    Flex({
256      direction: FlexDirection.Column,
257      alignItems: ItemAlign.Center,
258      justifyContent: FlexAlign.Center
259    }) {
260      Image(this.tabItem.getIcon(this.tabItem.isSelected))
261        .height($r('app.float.icon_size'))
262        .width($r('app.float.icon_size'))
263        .objectFit(ImageFit.Fill)
264        .margin({
265          bottom: $r('app.float.tab_bar_image_bottom')
266        })
267      Text(this.tabItem.name)
268        .fontSize($r('app.float.tab_bar_text_size'))
269        .fontWeight(FontWeight.Medium)
270        .fontColor(this.tabItem.getTextColor())
271    }
272    .key('Tab' + this.tabItem.componentKey)
273    .padding({
274      top: $r('app.float.tab_bar_padding_top'),
275      left: $r('app.float.tab_bar_padding_left'),
276      right: $r('app.float.tab_bar_padding_right'),
277      bottom: $r('app.float.tab_bar_padding_bottom'),
278    })
279    .height($r('app.float.tab_bar_vertical_height'))
280    .borderRadius($r('app.float.single_tab_margin'))
281  }
282}
283
284// For Album Set
285@Component
286export struct TabBarForAlbumSet {
287  @Consume isTabBarShow: boolean;
288  private currentIndex: number;
289  private tabs: TabItemWithText[] = [];
290  private controller: TabsController;
291
292  aboutToAppear(): void {
293    this.onTabSelected = this.onTabSelected.bind(this);
294    this.tabs[this.currentIndex].isSelected = true;
295    this.tabs.forEach((tab: TabItemWithText) => {
296      Log.info(TAG, `${JSON.stringify(tab.name)}, ${tab.isSelected}`);
297    });
298  }
299
300  build() {
301    if (this.isTabBarShow) {
302      Flex({
303        direction: FlexDirection.Row,
304        justifyContent: FlexAlign.Center,
305        alignItems: ItemAlign.Start
306      }) {
307        ForEach(this.tabs, (tab: TabItemWithText) => {
308          TabWithText({ tabItemWithText: tab, index: this.tabs.indexOf(tab), onTabSelected: this.onTabSelected })
309        }, tab => tab.name.id)
310      }
311      .width('100%')
312      .height($r('app.float.album_set_tab_bar_height'))
313      .padding({ left: $r('app.float.max_padding_start'), right: $r('app.float.max_padding_end') })
314      .backgroundColor($r('app.color.default_background_color'))
315    }
316  }
317
318  private onTabSelected(index: number) {
319    Log.info(TAG, `this.currentIndex: ${this.currentIndex} index: ${index}`);
320    this.currentIndex = index;
321    this.controller.changeIndex(this.currentIndex);
322    this.tabs.forEach((tab: TabItemWithText) => {
323      tab.isSelected = false;
324    })
325    Log.info(TAG, `select ${this.currentIndex}`);
326  }
327}
328
329// single tab which only has text
330// For Album Set
331@Component
332struct TabWithText {
333  @Consume isAlbumSetSelectedMode: boolean;
334  @ObjectLink tabItemWithText: TabItemWithText;
335  @State TabWidth: number = 0;
336  index: number;
337  onTabSelected: Function;
338
339  aboutToAppear(): void {
340    // Determine the length of the underline based on the font length
341    if (this.index == 0) {
342      this.TabWidth = px2vp(fp2px(Constants.TEXT_SIZE_SUB_TITLE2)) * 2;
343    } else {
344      this.TabWidth = px2vp(fp2px(Constants.TEXT_SIZE_SUB_TITLE2)) * 4;
345    }
346    Log.info(TAG, `index is ${this.index} and TabWidth is ${this.TabWidth}`);
347  }
348
349  build() {
350    Flex({
351      direction: FlexDirection.Column,
352      justifyContent: FlexAlign.Center,
353      alignItems: ItemAlign.Center
354    }) {
355      Text(this.tabItemWithText.name)
356        .fontSize(this.tabItemWithText.getTextSize())
357        .fontWeight(this.tabItemWithText.getTextWeight())
358        .fontColor(this.tabItemWithText.getTextColor())
359        .maxLines(1)
360        .margin({ top: $r('app.float.tab_bar_line_margin_top'),
361          left: $r('app.float.single_tab_margin'),
362          right: $r('app.float.single_tab_margin'),
363          bottom: $r('app.float.tab_bar_line_margin_top') })
364      Column()
365        .width(this.TabWidth)
366        .height($r('app.float.tab_bar_line_height'))
367        .borderRadius($r('app.float.tab_bar_line_radius'))
368        .backgroundColor(this.tabItemWithText.getTextColor())
369        .visibility(this.tabItemWithText.isSelected ? Visibility.Visible : Visibility.Hidden)
370    }
371    .height('100%')
372    .onClick(() => {
373      if (!this.isAlbumSetSelectedMode) {
374        this.onTabSelected && this.onTabSelected(this.index)
375        this.tabItemWithText.isSelected = true
376      }
377    })
378  }
379}