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 '@ohos/base/src/main/ets/utils/Log'; 17import { TabItem, TabItemWithText } from '../model/common/TabItem'; 18import broadcastManager from '@ohos/base/src/main/ets/manager/BroadcastManager'; 19import { Broadcast } from '@ohos/base/src/main/ets/utils/Broadcast'; 20import { BroadcastConstants } from '@ohos/base/src/main/ets/constants/BroadcastConstants'; 21import { Constants } from '../model/common/Constants'; 22import screenManager, { ColumnSize } from '@ohos/base/src/main/ets/manager/ScreenManager'; 23 24export enum DEVICE_TYPE { 25 DEVICE_PHONE, 26 DEVICE_PAD 27} 28 29@Component 30export struct TabBar { 31 private TAG: string = 'TabBar'; 32 @Consume isSelectedMode: boolean; 33 @Consume isAlbumSetSelectedMode: boolean; 34 private currentIndex: number; 35 @StorageLink('isSidebar') isSidebar: boolean = screenManager.isSidebar(); 36 private tabs: TabItem[] = [ 37 new TabItem($r('app.string.tab_timeline'), $r('app.media.ic_photos'), $r("app.media.ic_photos_active"), false), 38 new TabItem($r('app.string.tab_albums'), $r('app.media.ic_albums'), $r("app.media.ic_albums_active"), false) 39 ]; 40 private controller: TabsController; 41 private appBroadcast: Broadcast = broadcastManager.getBroadcast(); 42 deviceType: DEVICE_TYPE = DEVICE_TYPE.DEVICE_PHONE; 43 44 aboutToAppear(): void { 45 this.onTabSelected = this.onTabSelected.bind(this); 46 this.tabs[this.currentIndex].isSelected = true; 47 this.tabs.forEach((tab: TabItem) => { 48 Log.info(this.TAG, `${JSON.stringify(tab.name)} , ${tab.iconSelected}`); 49 }); 50 } 51 52 private onTabSelected(index: number) { 53 Log.debug(this.TAG, `this.currentIndex: ${this.currentIndex} index: ${index}`); 54 if (this.currentIndex == index) { 55 Log.error(this.TAG, `it is same: ${index}`); 56 this.appBroadcast.emit(BroadcastConstants.RESET_ZERO, [index]); 57 } 58 this.currentIndex = index; 59 this.controller.changeIndex(this.currentIndex); 60 this.tabs.forEach((tab: TabItem) => { 61 tab.isSelected = false; 62 }) 63 64 Log.info(this.TAG, `select ${this.currentIndex}`); 65 } 66 67 build() { 68 if (this.isSidebar) { 69 Flex({ 70 direction: FlexDirection.Column, 71 alignItems: ItemAlign.Center, 72 justifyContent: FlexAlign.Center 73 }) { 74 Column() { 75 ForEach(this.tabs, (tab: TabItem) => { 76 Stack() { 77 Tab({ tabItem: tab, index: this.tabs.indexOf(tab), onTabSelected: this.onTabSelected }) 78 }.layoutWeight(1) 79 }, tab => tab.name.id) 80 } 81 .height(DEVICE_TYPE.DEVICE_PAD == this.deviceType ? $r('app.float.horizontal_width') : '100%') 82 } 83 .markAnchor({ x: '0%', y: '0%' }) 84 .position({ x: '0%', y: '0%' }) 85 .width($r('app.float.tab_bar_width')) 86 .backgroundColor($r('app.color.default_background_color')) 87 } else { 88 Flex({ 89 direction: FlexDirection.Row, 90 alignItems: ItemAlign.Center, 91 justifyContent: FlexAlign.Center 92 }) { 93 ForEach(this.tabs, (tab: TabItem) => { 94 Stack() { 95 Tab({ tabItem: tab, index: this.tabs.indexOf(tab), onTabSelected: this.onTabSelected }) 96 }.layoutWeight(1) 97 }, tab => tab.name.id) 98 } 99 .markAnchor({ x: '0%', y: '100%' }) 100 .position({ x: '0%', y: '100%' }) 101 .visibility((this.isSelectedMode || this.isAlbumSetSelectedMode) ? Visibility.None : Visibility.Visible) 102 .height('56vp') 103 .backgroundColor($r('app.color.default_background_color')) 104 } 105 } 106} 107 108// single tab 109@Component 110struct Tab { 111 tabItem: TabItem; 112 @State isSelected: boolean = false; 113 index: number; 114 onTabSelected: Function; 115 appBroadcast: Broadcast = broadcastManager.getBroadcast(); 116 117 aboutToAppear() { 118 this.isSelected = this.tabItem.isSelected; 119 this.appBroadcast.on(BroadcastConstants.RESET_TABBAR_SELECTED_STATUE, (pageNumber: number) => { 120 this.isSelected = this.index == pageNumber; 121 }) 122 } 123 124 build() { 125 Flex({ 126 direction: FlexDirection.Column, 127 alignItems: ItemAlign.Center, 128 justifyContent: FlexAlign.Center 129 }) { 130 Stack() { 131 Image(this.tabItem.getIcon(this.isSelected)) 132 .height($r('app.float.icon_size')) 133 .width($r('app.float.icon_size')) 134 .objectFit(ImageFit.Fill) 135 } 136 137 Text(this.tabItem.name) 138 .fontSize($r('sys.float.ohos_id_text_size_caption1')) 139 .fontFamily($r('app.string.id_text_font_family_medium')) 140 .fontColor(this.tabItem.getTextColor(this.isSelected)) 141 .padding({ 142 top: $r('app.float.tab_bar_text_padding_top'), 143 right: $r('app.float.tab_bar_text_padding_horizontal'), 144 left: $r('app.float.tab_bar_text_padding_horizontal') 145 }) 146 } 147 .onClick(() => { 148 this.onTabSelected && this.onTabSelected(this.index); 149 this.tabItem.isSelected = true; 150 this.appBroadcast.emit(BroadcastConstants.RESET_TABBAR_SELECTED_STATUE, [this.index]); 151 }) 152 } 153} 154 155// For Album Set 156@Component 157export struct TabBarForAlbumSet { 158 private TAG: string = 'TabBarForAlbumSet' 159 @Consume isTabBarShow: boolean; 160 private currentIndex: number; 161 private tabs: TabItemWithText[] = []; 162 private controller: TabsController; 163 @State tabWidth: string = '100%'; 164 @State tabCol: Resource = $r('app.float.album_tab_col_4_gap'); 165 @StorageLink('isSidebar') isSidebar: boolean = screenManager.isSidebar(); 166 167 aboutToAppear(): void { 168 this.onTabSelected = this.onTabSelected.bind(this); 169 this.tabs[this.currentIndex].isSelected = true; 170 this.tabs.forEach((tab: TabItemWithText) => { 171 Log.info(this.TAG, `${JSON.stringify(tab.name)}, ${tab.isSelected}`); 172 }); 173 let col = screenManager.getScreenColumns(); 174 if (col < ColumnSize.COLUMN_EIGHT) { 175 this.tabWidth = '100%'; 176 this.tabCol = $r('app.float.album_tab_col_4_gap'); 177 } else { 178 let sideWidth = this.isSidebar ? Constants.TAB_BAR_WIDTH : 0; 179 this.tabWidth = (screenManager.getWinWidth() - sideWidth) / Constants.NUMBER_2 + 'vp'; 180 this.tabCol = $r('app.float.album_tab_col_8_gap'); 181 } 182 Log.info(this.TAG, `album tabs item width: ${this.tabWidth}, col: ${col}`); 183 } 184 185 private onTabSelected(index: number) { 186 Log.info(this.TAG, `this.currentIndex: ${this.currentIndex} index: ${index}`); 187 this.currentIndex = index; 188 this.controller.changeIndex(this.currentIndex); 189 this.tabs.forEach((tab: TabItemWithText) => { 190 tab.isSelected = false; 191 }) 192 Log.info(this.TAG, `select ${this.currentIndex}`); 193 } 194 195 build() { 196 Flex({ 197 direction: FlexDirection.Row, 198 justifyContent: FlexAlign.Center, 199 alignItems: ItemAlign.Start 200 }) { 201 Grid() { 202 ForEach(this.tabs, (tab: TabItemWithText) => { 203 GridItem() { 204 TabWithText({ 205 tabItemWithText: tab, 206 index: this.tabs.indexOf(tab), 207 onTabSelected: this.onTabSelected 208 }) 209 } 210 }, tab => tab.name.id) 211 } 212 .width(this.tabWidth) 213 .columnsTemplate('1fr '.repeat(this.tabs.length)) 214 .columnsGap(this.tabCol) 215 } 216 .width('100%') 217 .height($r('app.float.album_set_tab_bar_height')) 218 .padding({ left: $r('app.float.max_padding_start'), right: $r('app.float.max_padding_end') }) 219 .backgroundColor($r('app.color.default_background_color')) 220 } 221} 222 223// single tab which only has text 224// For Album Set 225@Component 226struct TabWithText { 227 private TAG: string = 'TabWithText' 228 @Consume isAlbumSetSelectedMode: boolean; 229 tabItemWithText: TabItemWithText; 230 @State TabWidth: number = 0; 231 index: number; 232 onTabSelected: Function; 233 234 aboutToAppear(): void { 235 // Determine the length of the underline based on the font length 236 if (this.index == 0) { 237 this.TabWidth = px2vp(fp2px(Constants.TEXT_SIZE_SUB_TITLE2)) * 2; 238 } else { 239 this.TabWidth = px2vp(fp2px(Constants.TEXT_SIZE_SUB_TITLE2)) * 4; 240 } 241 Log.info(this.TAG, `index is ${this.index} and TabWidth is ${this.TabWidth}`); 242 } 243 244 build() { 245 Flex({ 246 direction: FlexDirection.Column, 247 justifyContent: FlexAlign.Center, 248 alignItems: ItemAlign.Center 249 }) { 250 Text(this.tabItemWithText.name) 251 .fontSize(this.tabItemWithText.getTextSize()) 252 .fontWeight(this.tabItemWithText.getTextWeight()) 253 .fontColor(this.tabItemWithText.getTextColor()) 254 .maxLines(1) 255 .margin({ top: $r('app.float.tab_bar_line_margin_top'), 256 left: $r('app.float.single_tab_margin'), 257 right: $r('app.float.single_tab_margin'), 258 bottom: $r('app.float.tab_bar_line_margin_top') }) 259 Column() 260 .width(this.TabWidth) 261 .height($r('app.float.tab_bar_line_height')) 262 .borderRadius($r('app.float.tab_bar_line_radius')) 263 .backgroundColor(this.tabItemWithText.getTextColor()) 264 .visibility(this.tabItemWithText.isSelected ? Visibility.Visible : Visibility.Hidden) 265 } 266 .height('100%') 267 .width('100%') 268 .onClick(() => { 269 if (!this.isAlbumSetSelectedMode) { 270 this.onTabSelected && this.onTabSelected(this.index) 271 this.tabItemWithText.isSelected = true 272 } 273 }) 274 } 275}