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