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 16import {isNfcAvailable} from '../../../../../../../../common/src/main/ets/default/Constants'; 17import Log from '../../../../../../../../common/src/main/ets/default/Log' 18import { StatusBarData, StatusBarBackgroundData, StatusBarConfig } from '../common/Constants' 19import { FASlotName } from '../../../../../../../../common/src/main/ets/default/Constants' 20import { TintContentInfo } from '../../../../../../../../common/src/main/ets/default/TintStateManager' 21import StyleConfigurationCommon, { CommonStyle 22} from '../../../../../../../../common/src/main/ets/default/StyleConfiguration' 23import StyleConfiguration, { StatusBarNotificationIconStyle, VerticalStatusBarItemLoadComponentStyle 24} from '../common/StyleConfiguration' 25import ViewModel from '../viewmodel/StatusBarVM' 26import { StringArray } from '../viewmodel/StatusBarVM' 27import IconItemComponent from './IconItemComponent' 28import BatteryIcon from '../../../../../../../batterycomponent/src/main/ets/default/pages/batteryIcon' 29import ClockIcon from '../../../../../../../clockcomponent/src/main/ets/default/pages/clockIcon' 30import AirplaneIcon from '../../../../../../../airplanecomponent/src/main/ets/default/pages/StatusBarIconItemAirplaneComponent' 31import WifiIcon from '../../../../../../../wificomponent/src/main/ets/default/pages/wifiIcon' 32import BluetoothIcon from '../../../../../../../bluetoothcomponent/src/main/ets/com/ohos/pages/StatusBarIconItemBluetoothComponent' 33import SignalIcon from '../../../../../../../signalcomponent/src/main/ets/default/pages/signalIcon' 34import CapsuleIcon from '../../../../../../../capsulecomponent/src/main/ets/default/pages/CapsuleIcon' 35import LocationIcon from '../../../../../../../locationcomponent/src/main/ets/com/ohos/pages/StatusBarIconItemLocationComponent' 36import RingModeIcon from '../../../../../../../ringmodecomponent/src/main/ets/com/ohos/pages/StatusBarIconItemRingModeComponent' 37import NfcIcon from '../../../../../../../nfccomponent/src/main/ets/com/ohos/pages/StatusBarIconItemNFComponent' 38import { NotificationItemData } from '@ohos/common'; 39import { BusinessError, commonEventManager } from '@kit.BasicServicesKit'; 40 41const TAG = 'StatusBarComponent' 42const TAG_StatusBarGroup = 'StatusBarGroup' 43const TAG_VerticalStatusBarItemLoadComponent = 'VerticalStatusBarItemLoadComponent' 44const TAG_StatusBarItemLoadComponent = 'StatusBarItemLoadComponent' 45const TAG_StatusBarEmptyIcon = 'StatusBarEmptyIcon' 46const TAG_StatusBarNotificationIcon = 'StatusBarNotificationIcon' 47const TAG_StatusBarBackground = 'StatusBarBackground' 48 49interface Item { 50 index: number; 51 data: NotificationItemData[]; 52} 53 54@Component 55export default struct StatusBarComponent { 56 private mStatusBarComponentConfig: StatusBarConfig | undefined = undefined 57 @State mStatusBarData: StatusBarData = ViewModel.getStatusBarData() 58 private moduleName: string = '' 59 60 aboutToAppear() { 61 AppStorage.SetOrCreate('size', $r("app.float.status_bar_margin_left_right")); 62 Log.showInfo(TAG, `aboutToAppear Start, mStatusBarComponentConfig: ${JSON.stringify(this.mStatusBarComponentConfig)}`); 63 this.initViewModel(this.moduleName); 64 } 65 66 aboutToDisappear() { 67 Log.showInfo(TAG, `aboutToDisappear`); 68 } 69 70 initViewModel(moduleName: string) { 71 Log.showInfo(TAG, `initViewModel`); 72 ViewModel.initViewModel(this.mStatusBarComponentConfig, moduleName); 73 } 74 75 build() { 76 Stack() { 77 StatusBarBackground() 78 if (this.mStatusBarData.showHorizontal) { 79 Row() { 80 StatusBarGroup({ 81 index: 0, 82 mLayoutWeight: 1, 83 mAlignItems: HorizontalAlign.Start 84 }) 85 StatusBarGroup({ 86 index: 1, 87 mLayoutWeight: 0, 88 mAlignItems: HorizontalAlign.Center 89 }) 90 StatusBarGroup({ 91 index: 2, 92 mLayoutWeight: 1, 93 mAlignItems: HorizontalAlign.End 94 }) 95 } 96 .padding({ left: $r('app.float.status_bar_padding_start'), right: $r('app.float.status_bar_padding_end') }) 97 .width('100%') 98 .height('100%') 99 } else { 100 Column() { 101 StatusBarGroup({ 102 index: 0, 103 mLayoutWeight: 1, 104 mAlignItems: VerticalAlign.Center 105 }) 106 StatusBarGroup({ 107 index: 1, 108 mLayoutWeight: 0, 109 mAlignItems: VerticalAlign.Center 110 }) 111 StatusBarGroup({ 112 index: 2, 113 mLayoutWeight: 1, 114 mAlignItems: VerticalAlign.Center 115 }) 116 } 117 .width('100%') 118 .height('100%') 119 } 120 }.onClick(() => { 121 try { 122 commonEventManager.publish('usual.event.CLICK_STATUSBAR', (err: BusinessError) => { 123 if (err) { 124 Log.showError(TAG, `Failed to publish click event. Code is ${err.code}, message is ${err.message}`); 125 } else { 126 Log.showInfo(TAG, `Succeeded in publishing click event.`); 127 } 128 }) 129 } catch (error) { 130 let err: BusinessError = error as BusinessError; 131 Log.showError(TAG, `Failed to publish click event. Code is ${err.code}, message is ${err.message}`); 132 } 133 }) 134 .width('100%') 135 .height('100%') 136 } 137} 138 139@Component 140struct StatusBarBackground { 141 @State mStatusBarData: StatusBarData = ViewModel.getStatusBarData() 142 @State mBackgroundDatas: StatusBarBackgroundData[] = ViewModel.getBackgroundDatas() 143 144 aboutToAppear() { 145 Log.showInfo(TAG_StatusBarBackground, `aboutToAppear`); 146 } 147 148 aboutToDisappear() { 149 Log.showInfo(TAG_StatusBarBackground, `aboutToDisAppear`); 150 } 151 152 build() { 153 if (this.mStatusBarData.showHorizontal) { 154 Row() { 155 ForEach(this.mBackgroundDatas, (data: StatusBarBackgroundData) => { 156 if (data.width > 0) { 157 Column() { 158 } 159 .width(data.width + 'px') 160 .height('100%') 161 .backgroundColor(data.backgroundColor) 162 } 163 }) 164 } 165 .width('100%') 166 .height('100%') 167 } else { 168 Column() { 169 ForEach(this.mBackgroundDatas, (data: StatusBarBackgroundData) => { 170 if (data.width > 0) { 171 Column() { 172 } 173 .width('100%') 174 .height(data.width + 'px') 175 .backgroundColor(data.backgroundColor) 176 } 177 }) 178 } 179 .width('100%') 180 .height('100%') 181 } 182 } 183} 184 185@Component 186struct StatusBarGroup { 187 @StorageLink('StatusBarLayout') mStatusBarLayout: string[][] = [[], [], []] 188 private mLayoutWeight: number = 1 189 private mAlignItems: number = HorizontalAlign.Center; 190 private index: number = -1; 191 @State mStatusBarData: StatusBarData = ViewModel.getStatusBarData() 192 193 aboutToAppear() { 194 Log.showInfo(TAG_StatusBarGroup, `aboutToAppear, mLayoutWeight: ${this.mLayoutWeight} mAlignItems: ${this.mAlignItems} `); 195 } 196 197 aboutToDisappear() { 198 Log.showInfo(TAG_StatusBarGroup, `aboutToDisAppear`); 199 } 200 201 build() { 202 if (this.mStatusBarData.showHorizontal) { 203 Column() { 204 Row() { 205 ForEach(this.mStatusBarLayout[this.index], (componentName: string) => { 206 StatusBarItemLoadComponent({ 207 mComponentName: componentName 208 }) 209 }, (componentName: string) => componentName) 210 }.height('100%') 211 } 212 .alignItems(this.mAlignItems) 213 .layoutWeight(this.mLayoutWeight) 214 .height('100%') 215 } else { 216 Row() { 217 Column() { 218 ForEach(this.mStatusBarLayout[this.index], (componentName: string) => { 219 VerticalStatusBarItemLoadComponent({ 220 mComponentName: componentName 221 }) 222 }, (componentName: string) => componentName) 223 }.width('100%') 224 .alignItems(HorizontalAlign.Start) 225 } 226 .alignItems(this.mAlignItems) 227 .width('100%') 228 .layoutWeight(this.mLayoutWeight) 229 } 230 } 231} 232 233@Component 234struct VerticalStatusBarItemLoadComponent { 235 private mComponentName: string = '' 236 @State mComponentHeight: number = 0 237 @State style: VerticalStatusBarItemLoadComponentStyle = StyleConfiguration.getVerticalStatusBarItemLoadComponentStyle() 238 239 aboutToAppear() { 240 Log.showInfo(TAG_VerticalStatusBarItemLoadComponent, `aboutToAppear, mComponentName: ${this.mComponentName}`); 241 } 242 243 aboutToDisappear() { 244 Log.showInfo(TAG_VerticalStatusBarItemLoadComponent, `aboutToDisAppear, mComponentName: ${this.mComponentName}`); 245 } 246 247 build() { 248 Row() { 249 StatusBarItemLoadComponent({ 250 mComponentName: this.mComponentName 251 }) 252 } 253 .height(this.mComponentHeight + 'px') 254 .onAreaChange((e, e2) => { 255 Log.showInfo(TAG_VerticalStatusBarItemLoadComponent, `onAreaChange, mComponentName: ${this.mComponentName} e: ${JSON.stringify(e)} e2: ${JSON.stringify(e2)}`); 256 this.mComponentHeight = e2.width > 0 ? this.style.statusBarVerticalComponentHeight : 0 257 Log.showInfo(TAG_VerticalStatusBarItemLoadComponent, `onAreaChange, mComponentName: ${this.mComponentName} mComponentHeight: ${this.mComponentHeight}`); 258 }) 259 } 260} 261 262@Component 263struct StatusBarItemLoadComponent { 264 private mComponentName: string = '' 265 aboutToAppear() { 266 Log.showInfo(TAG_StatusBarItemLoadComponent, `aboutToAppear, mComponentName: ${this.mComponentName} `) 267 } 268 269 aboutToDisappear() { 270 Log.showInfo(TAG_StatusBarGroup, `aboutToDisAppear, mComponentName: ${this.mComponentName} `) 271 } 272 273 build() { 274 Row() { 275 if (this.mComponentName == FASlotName.EMPTY) { 276 StatusBarEmptyIcon() 277 } else if (this.mComponentName == FASlotName.WIFI) { 278 WifiIcon() 279 } else if (this.mComponentName == FASlotName.BLUETOOTH) { 280 BluetoothIcon() 281 } else if (this.mComponentName == FASlotName.SIGNAL) { 282 SignalIcon() 283 } else if (this.mComponentName == FASlotName.CLOCK) { 284 ClockIcon() 285 } else if (this.mComponentName == FASlotName.BATTERY) { 286 BatteryIcon() 287 } else if (this.mComponentName == FASlotName.AIR_PLANE) { 288 AirplaneIcon() 289 } else if (this.mComponentName == FASlotName.CAPSULE) { 290 CapsuleIcon() 291 } else if (this.mComponentName == FASlotName.NOTIFICATION) { 292 StatusBarNotificationIcon() 293 } else if (this.mComponentName == FASlotName.LOCATION) { 294 LocationIcon() 295 } else if (this.mComponentName == FASlotName.RING_MODE) { 296 RingModeIcon() 297 } else if (this.mComponentName == FASlotName.NFC) { 298 if (isNfcAvailable()) { 299 NfcIcon() 300 } 301 } else { 302 IconItemComponent({ 303 keyId: this.mComponentName 304 }) 305 } 306 }.height('100%') 307 .onAreaChange((e: Area, e2: Area) => { 308 Log.showInfo(TAG_StatusBarItemLoadComponent, `onAreaChange, componentName: ${this.mComponentName}}, new area: ${JSON.stringify(e2)} `) 309 ViewModel.updateComponentArea(this.mComponentName, e2) 310 }) 311 } 312} 313 314@Component 315struct StatusBarEmptyIcon { 316 @StorageLink('StatusBarEmptyWidth') mStatusBarEmptyWidth: number = 0 317 @State mTintContentInfo: TintContentInfo = ViewModel.getEmptyTintContentInfo() 318 319 aboutToAppear() { 320 Log.showInfo(TAG_StatusBarEmptyIcon, `aboutToAppear, mStatusBarEmptyWidth: ${this.mStatusBarEmptyWidth} `) 321 } 322 323 aboutToDisappear() { 324 Log.showInfo(TAG_StatusBarEmptyIcon, `aboutToDisAppear`); 325 } 326 327 build() { 328 Row().width(this.mStatusBarEmptyWidth).height('100%') 329 } 330} 331 332@Component 333struct StatusBarNotificationIcon { 334 @StorageLink('notificationList') notificationList: NotificationItemData[][] = [] 335 @StorageLink('StatusCoefficient') StatusCoefficient: number = 1.0 336 @State mTintContentInfo: TintContentInfo = ViewModel.getNotificationTintContentInfo() 337 @State styleCommon: CommonStyle = StyleConfigurationCommon.getCommonStyle() 338 @State style: StatusBarNotificationIconStyle = StyleConfiguration.getStatusBarNotificationIconStyle() 339 340 aboutToAppear() { 341 Log.showInfo(TAG_StatusBarNotificationIcon, `aboutToAppear`); 342 } 343 344 aboutToDisappear() { 345 Log.showInfo(TAG_StatusBarNotificationIcon, `aboutToDisAppear`); 346 } 347 348 build() { 349 Row() { 350 if (this.notificationList.length > 0) { 351 Row().height(1).width(this.styleCommon.statusBarMarginLeftRight) 352 } 353 if (this.notificationList.length > 3) { 354 ForEach(this.notificationList.slice(0, 3), (item: NotificationItemData[]) => { 355 Image(item[0].smallIcon) 356 .objectFit(ImageFit.ScaleDown) 357 .height(this.style.iconHeight) 358 .width(this.style.iconWidth) 359 .margin({ right: this.style.iconSpace }) 360 .fillColor(this.mTintContentInfo.contentColor) 361 }) 362 Row() { 363 Text('...') 364 .fontSize(this.styleCommon.statusBarFontSize) 365 .fontColor(this.mTintContentInfo.contentColor) 366 } 367 } else { 368 ForEach(this.notificationList.map((item, index1) => { 369 let res: Item = { index: index1, data: item } 370 return res 371 }), (res: Item) => { 372 if (res.index > 0) { 373 Row().height(1).width(this.style.iconSpace) 374 } 375 Image(res.data[0].smallIcon) 376 .objectFit(ImageFit.ScaleDown) 377 .height(this.style.iconHeight) 378 .width(this.style.iconWidth) 379 .fillColor(this.mTintContentInfo.contentColor) 380 }) 381 } 382 if (this.notificationList.length > 0) { 383 Row().height(1).width(this.styleCommon.statusBarMarginLeftRight) 384 } 385 } 386 .height('100%') 387 } 388} 389