123b3eb3cSopenharmony_ci/*
223b3eb3cSopenharmony_ci * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
323b3eb3cSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
423b3eb3cSopenharmony_ci * you may not use this file except in compliance with the License.
523b3eb3cSopenharmony_ci * You may obtain a copy of the License at
623b3eb3cSopenharmony_ci *
723b3eb3cSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
823b3eb3cSopenharmony_ci *
923b3eb3cSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1023b3eb3cSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1123b3eb3cSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1223b3eb3cSopenharmony_ci * See the License for the specific language governing permissions and
1323b3eb3cSopenharmony_ci * limitations under the License.
1423b3eb3cSopenharmony_ci */
1523b3eb3cSopenharmony_ci
1623b3eb3cSopenharmony_ciimport { KeyCode } from '@ohos.multimodalInput.keyCode'
1723b3eb3cSopenharmony_ciimport window from '@ohos.window'
1823b3eb3cSopenharmony_ciimport common from '@ohos.app.ability.common'
1923b3eb3cSopenharmony_ciimport { BusinessError } from '@kit.BasicServicesKit'
2023b3eb3cSopenharmony_ciimport { hilog } from '@kit.PerformanceAnalysisKit'
2123b3eb3cSopenharmony_ci
2223b3eb3cSopenharmony_ciexport interface ComposeTitleBarMenuItem {
2323b3eb3cSopenharmony_ci  value: ResourceStr;
2423b3eb3cSopenharmony_ci  isEnabled?: boolean;
2523b3eb3cSopenharmony_ci  action?: () => void;
2623b3eb3cSopenharmony_ci  label?: ResourceStr;
2723b3eb3cSopenharmony_ci}
2823b3eb3cSopenharmony_ci
2923b3eb3cSopenharmony_ciconst PUBLIC_MORE = $r('sys.media.ohos_ic_public_more')
3023b3eb3cSopenharmony_ciconst PUBLIC_BACK: Resource = $r('sys.media.ohos_ic_back')
3123b3eb3cSopenharmony_ciconst TEXT_EDITABLE_DIALOG = '18.3fp'
3223b3eb3cSopenharmony_ciconst IMAGE_SIZE = '64vp'
3323b3eb3cSopenharmony_ciconst MAX_DIALOG = '256vp'
3423b3eb3cSopenharmony_ciconst MIN_DIALOG = '216vp'
3523b3eb3cSopenharmony_ci
3623b3eb3cSopenharmony_ci@Component
3723b3eb3cSopenharmony_cistruct ComposeTitleBar {
3823b3eb3cSopenharmony_ci  item: ComposeTitleBarMenuItem | undefined = undefined
3923b3eb3cSopenharmony_ci  title: ResourceStr = ''
4023b3eb3cSopenharmony_ci  subtitle: ResourceStr = ''
4123b3eb3cSopenharmony_ci  menuItems?: Array<ComposeTitleBarMenuItem> = [];
4223b3eb3cSopenharmony_ci
4323b3eb3cSopenharmony_ci  @State titleMaxWidth: number = 0
4423b3eb3cSopenharmony_ci  @State fontSize: number = 1;
4523b3eb3cSopenharmony_ci
4623b3eb3cSopenharmony_ci  private static readonly totalHeight = 56
4723b3eb3cSopenharmony_ci  private static readonly leftPadding = 12
4823b3eb3cSopenharmony_ci  private static readonly rightPadding = 12
4923b3eb3cSopenharmony_ci  private static readonly portraitImageSize = 40
5023b3eb3cSopenharmony_ci  private static readonly portraitImageLeftPadding = 4
5123b3eb3cSopenharmony_ci  private static readonly portraitImageRightPadding = 16
5223b3eb3cSopenharmony_ci  private static instanceCount = 0
5323b3eb3cSopenharmony_ci
5423b3eb3cSopenharmony_ci  build() {
5523b3eb3cSopenharmony_ci    Flex({
5623b3eb3cSopenharmony_ci      justifyContent: FlexAlign.SpaceBetween,
5723b3eb3cSopenharmony_ci      alignItems: ItemAlign.Stretch
5823b3eb3cSopenharmony_ci    }) {
5923b3eb3cSopenharmony_ci      Row() {
6023b3eb3cSopenharmony_ci        ImageMenuItem({ item: {
6123b3eb3cSopenharmony_ci          value: PUBLIC_BACK,
6223b3eb3cSopenharmony_ci          isEnabled: true,
6323b3eb3cSopenharmony_ci          action: () => this.getUIContext()?.getRouter()?.back()
6423b3eb3cSopenharmony_ci        }, index: -1 })
6523b3eb3cSopenharmony_ci
6623b3eb3cSopenharmony_ci        if (this.item !== undefined) {
6723b3eb3cSopenharmony_ci          Image(this.item.value)
6823b3eb3cSopenharmony_ci            .width(ComposeTitleBar.portraitImageSize)
6923b3eb3cSopenharmony_ci            .height(ComposeTitleBar.portraitImageSize)
7023b3eb3cSopenharmony_ci            .margin({
7123b3eb3cSopenharmony_ci              left: $r('sys.float.ohos_id_text_paragraph_margin_xs'),
7223b3eb3cSopenharmony_ci              right: $r('sys.float.ohos_id_text_paragraph_margin_m')
7323b3eb3cSopenharmony_ci            })
7423b3eb3cSopenharmony_ci            .focusable(false)
7523b3eb3cSopenharmony_ci            .borderRadius(ImageMenuItem.buttonBorderRadius)
7623b3eb3cSopenharmony_ci        }
7723b3eb3cSopenharmony_ci
7823b3eb3cSopenharmony_ci        Column() {
7923b3eb3cSopenharmony_ci          if (this.title !== undefined) {
8023b3eb3cSopenharmony_ci            Row() {
8123b3eb3cSopenharmony_ci              Text(this.title)
8223b3eb3cSopenharmony_ci                .fontWeight(FontWeight.Medium)
8323b3eb3cSopenharmony_ci                .fontSize($r('sys.float.ohos_id_text_size_headline8'))
8423b3eb3cSopenharmony_ci                .fontColor($r('sys.color.ohos_id_color_titlebar_text'))
8523b3eb3cSopenharmony_ci                .maxLines(this.subtitle !== undefined ? 1 : 2)
8623b3eb3cSopenharmony_ci                .textOverflow({ overflow: TextOverflow.Ellipsis })
8723b3eb3cSopenharmony_ci                .constraintSize({ maxWidth: this.titleMaxWidth })
8823b3eb3cSopenharmony_ci            }
8923b3eb3cSopenharmony_ci            .justifyContent(FlexAlign.Start)
9023b3eb3cSopenharmony_ci          }
9123b3eb3cSopenharmony_ci          if (this.subtitle !== undefined) {
9223b3eb3cSopenharmony_ci            Row() {
9323b3eb3cSopenharmony_ci              Text(this.subtitle)
9423b3eb3cSopenharmony_ci                .fontSize($r('sys.float.ohos_id_text_size_over_line'))
9523b3eb3cSopenharmony_ci                .fontColor($r('sys.color.ohos_id_color_titlebar_subtitle_text'))
9623b3eb3cSopenharmony_ci                .maxLines(1)
9723b3eb3cSopenharmony_ci                .textOverflow({ overflow: TextOverflow.Ellipsis })
9823b3eb3cSopenharmony_ci                .constraintSize({ maxWidth: this.titleMaxWidth })
9923b3eb3cSopenharmony_ci            }
10023b3eb3cSopenharmony_ci            .justifyContent(FlexAlign.Start)
10123b3eb3cSopenharmony_ci          }
10223b3eb3cSopenharmony_ci        }
10323b3eb3cSopenharmony_ci        .justifyContent(FlexAlign.Start)
10423b3eb3cSopenharmony_ci        .alignItems(HorizontalAlign.Start)
10523b3eb3cSopenharmony_ci        .constraintSize({ maxWidth: this.titleMaxWidth })
10623b3eb3cSopenharmony_ci      }
10723b3eb3cSopenharmony_ci      .margin({ left: $r('sys.float.ohos_id_default_padding_start') })
10823b3eb3cSopenharmony_ci
10923b3eb3cSopenharmony_ci      if (this.menuItems !== undefined && this.menuItems.length > 0) {
11023b3eb3cSopenharmony_ci        CollapsibleMenuSection({ menuItems: this.menuItems, index: 1 + ComposeTitleBar.instanceCount++ })
11123b3eb3cSopenharmony_ci      }
11223b3eb3cSopenharmony_ci    }
11323b3eb3cSopenharmony_ci    .width('100%')
11423b3eb3cSopenharmony_ci    .height(ComposeTitleBar.totalHeight)
11523b3eb3cSopenharmony_ci    .backgroundColor($r('sys.color.ohos_id_color_background'))
11623b3eb3cSopenharmony_ci    .onAreaChange((_oldValue: Area, newValue: Area) => {
11723b3eb3cSopenharmony_ci      let newWidth = Number(newValue.width)
11823b3eb3cSopenharmony_ci      if (this.menuItems !== undefined) {
11923b3eb3cSopenharmony_ci        let menusLength = this.menuItems.length
12023b3eb3cSopenharmony_ci        if (menusLength >= CollapsibleMenuSection.maxCountOfVisibleItems) {
12123b3eb3cSopenharmony_ci          newWidth = newWidth - ImageMenuItem.imageHotZoneWidth * CollapsibleMenuSection.maxCountOfVisibleItems
12223b3eb3cSopenharmony_ci        } else if (menusLength > 0) {
12323b3eb3cSopenharmony_ci          newWidth = newWidth - ImageMenuItem.imageHotZoneWidth * menusLength
12423b3eb3cSopenharmony_ci        }
12523b3eb3cSopenharmony_ci      }
12623b3eb3cSopenharmony_ci      this.titleMaxWidth = newWidth
12723b3eb3cSopenharmony_ci      this.titleMaxWidth -= ComposeTitleBar.leftPadding
12823b3eb3cSopenharmony_ci      this.titleMaxWidth -= ImageMenuItem.imageHotZoneWidth
12923b3eb3cSopenharmony_ci      if (this.item !== undefined) {
13023b3eb3cSopenharmony_ci        this.titleMaxWidth -= ComposeTitleBar.portraitImageLeftPadding +
13123b3eb3cSopenharmony_ci          ComposeTitleBar.portraitImageSize +
13223b3eb3cSopenharmony_ci          ComposeTitleBar.portraitImageRightPadding
13323b3eb3cSopenharmony_ci      }
13423b3eb3cSopenharmony_ci      this.titleMaxWidth -= ComposeTitleBar.rightPadding
13523b3eb3cSopenharmony_ci    })
13623b3eb3cSopenharmony_ci  }
13723b3eb3cSopenharmony_ci}
13823b3eb3cSopenharmony_ci
13923b3eb3cSopenharmony_ci@Component
14023b3eb3cSopenharmony_cistruct CollapsibleMenuSection {
14123b3eb3cSopenharmony_ci  menuItems?: Array<ComposeTitleBarMenuItem> = [];
14223b3eb3cSopenharmony_ci  item: ComposeTitleBarMenuItem = {
14323b3eb3cSopenharmony_ci    value: PUBLIC_MORE,
14423b3eb3cSopenharmony_ci    label: $r('sys.string.ohos_toolbar_more'),
14523b3eb3cSopenharmony_ci  } as ComposeTitleBarMenuItem;
14623b3eb3cSopenharmony_ci  index: number = 0
14723b3eb3cSopenharmony_ci  longPressTime: number = 500;
14823b3eb3cSopenharmony_ci  minFontSize: number = 1.75;
14923b3eb3cSopenharmony_ci  isFollowingSystemFontScale: boolean = false;
15023b3eb3cSopenharmony_ci  maxFontScale: number = 1;
15123b3eb3cSopenharmony_ci  systemFontScale?: number = 1;
15223b3eb3cSopenharmony_ci
15323b3eb3cSopenharmony_ci  static readonly maxCountOfVisibleItems = 3
15423b3eb3cSopenharmony_ci  private static readonly focusPadding = 4
15523b3eb3cSopenharmony_ci  private static readonly marginsNum = 2
15623b3eb3cSopenharmony_ci  private firstFocusableIndex = -1
15723b3eb3cSopenharmony_ci
15823b3eb3cSopenharmony_ci  @State isPopupShown: boolean = false
15923b3eb3cSopenharmony_ci
16023b3eb3cSopenharmony_ci  @State isMoreIconOnFocus: boolean = false
16123b3eb3cSopenharmony_ci  @State isMoreIconOnHover: boolean = false
16223b3eb3cSopenharmony_ci  @State isMoreIconOnClick: boolean = false
16323b3eb3cSopenharmony_ci  @State fontSize: number = 1
16423b3eb3cSopenharmony_ci
16523b3eb3cSopenharmony_ci  dialogController: CustomDialogController | null = new CustomDialogController({
16623b3eb3cSopenharmony_ci    builder: ComposeTitleBarDialog({
16723b3eb3cSopenharmony_ci      cancel: () => {
16823b3eb3cSopenharmony_ci      },
16923b3eb3cSopenharmony_ci      confirm: () => {
17023b3eb3cSopenharmony_ci      },
17123b3eb3cSopenharmony_ci      itemComposeTitleDialog: this.item,
17223b3eb3cSopenharmony_ci      composeTitleBarDialog: this.item.label ? this.item.label : '',
17323b3eb3cSopenharmony_ci      fontSize: this.fontSize,
17423b3eb3cSopenharmony_ci    }),
17523b3eb3cSopenharmony_ci    maskColor: Color.Transparent,
17623b3eb3cSopenharmony_ci    isModal: true,
17723b3eb3cSopenharmony_ci    customStyle: true,
17823b3eb3cSopenharmony_ci  })
17923b3eb3cSopenharmony_ci
18023b3eb3cSopenharmony_ci  getMoreIconFgColor() {
18123b3eb3cSopenharmony_ci    return this.isMoreIconOnClick ?
18223b3eb3cSopenharmony_ci    $r('sys.color.ohos_id_color_titlebar_icon_pressed') :
18323b3eb3cSopenharmony_ci    $r('sys.color.ohos_id_color_titlebar_icon')
18423b3eb3cSopenharmony_ci  }
18523b3eb3cSopenharmony_ci
18623b3eb3cSopenharmony_ci  getMoreIconBgColor() {
18723b3eb3cSopenharmony_ci    if (this.isMoreIconOnClick) {
18823b3eb3cSopenharmony_ci      return $r('sys.color.ohos_id_color_click_effect')
18923b3eb3cSopenharmony_ci    } else if (this.isMoreIconOnHover) {
19023b3eb3cSopenharmony_ci      return $r('sys.color.ohos_id_color_hover')
19123b3eb3cSopenharmony_ci    } else {
19223b3eb3cSopenharmony_ci      return Color.Transparent
19323b3eb3cSopenharmony_ci    }
19423b3eb3cSopenharmony_ci  }
19523b3eb3cSopenharmony_ci
19623b3eb3cSopenharmony_ci  aboutToAppear() {
19723b3eb3cSopenharmony_ci    try {
19823b3eb3cSopenharmony_ci      let uiContent: UIContext = this.getUIContext();
19923b3eb3cSopenharmony_ci      this.isFollowingSystemFontScale = uiContent.isFollowingSystemFontScale();
20023b3eb3cSopenharmony_ci      this.maxFontScale = uiContent.getMaxFontScale();
20123b3eb3cSopenharmony_ci    } catch (err) {
20223b3eb3cSopenharmony_ci      let code: number = (err as BusinessError).code;
20323b3eb3cSopenharmony_ci      let message: string = (err as BusinessError).message;
20423b3eb3cSopenharmony_ci      hilog.error(0x3900, 'ComposeTitleBar', `Failed to init fontsizescale info, cause, code: ${code}, message: ${message}`);
20523b3eb3cSopenharmony_ci    }
20623b3eb3cSopenharmony_ci    if (this.menuItems) {
20723b3eb3cSopenharmony_ci      this.menuItems.forEach((item, index) => {
20823b3eb3cSopenharmony_ci        if (item.isEnabled && this.firstFocusableIndex == -1 &&
20923b3eb3cSopenharmony_ci          index > CollapsibleMenuSection.maxCountOfVisibleItems - 2) {
21023b3eb3cSopenharmony_ci          this.firstFocusableIndex = this.index * 1000 + index + 1
21123b3eb3cSopenharmony_ci        }
21223b3eb3cSopenharmony_ci      })
21323b3eb3cSopenharmony_ci    }
21423b3eb3cSopenharmony_ci  }
21523b3eb3cSopenharmony_ci
21623b3eb3cSopenharmony_ci  decideFontScale(): number {
21723b3eb3cSopenharmony_ci    try {
21823b3eb3cSopenharmony_ci      let uiContent: UIContext = this.getUIContext();
21923b3eb3cSopenharmony_ci      this.systemFontScale = (uiContent.getHostContext() as common.UIAbilityContext)?.config?.fontSizeScale ?? 1;
22023b3eb3cSopenharmony_ci      if (!this.isFollowingSystemFontScale) {
22123b3eb3cSopenharmony_ci        return 1;
22223b3eb3cSopenharmony_ci      }
22323b3eb3cSopenharmony_ci      return Math.min(this.systemFontScale, this.maxFontScale);
22423b3eb3cSopenharmony_ci    } catch (exception) {
22523b3eb3cSopenharmony_ci      let code: number = (exception as BusinessError).code;
22623b3eb3cSopenharmony_ci      let message: string = (exception as BusinessError).message;
22723b3eb3cSopenharmony_ci      hilog.error(0x3900, 'ComposeTitleBar', `Faild to decideFontScale,cause, code: ${code}, message: ${message}`);
22823b3eb3cSopenharmony_ci      return 1;
22923b3eb3cSopenharmony_ci    }
23023b3eb3cSopenharmony_ci  }
23123b3eb3cSopenharmony_ci
23223b3eb3cSopenharmony_ci
23323b3eb3cSopenharmony_ci  build() {
23423b3eb3cSopenharmony_ci    Column() {
23523b3eb3cSopenharmony_ci      Row() {
23623b3eb3cSopenharmony_ci        if (this.menuItems) {
23723b3eb3cSopenharmony_ci          if (this.menuItems.length <= CollapsibleMenuSection.maxCountOfVisibleItems) {
23823b3eb3cSopenharmony_ci            ForEach(this.menuItems, (item: ComposeTitleBarMenuItem, index:number) => {
23923b3eb3cSopenharmony_ci              ImageMenuItem({ item: item, index: this.index * 1000 + index + 1 })
24023b3eb3cSopenharmony_ci            })
24123b3eb3cSopenharmony_ci          } else {
24223b3eb3cSopenharmony_ci            ForEach(this.menuItems.slice(0, CollapsibleMenuSection.maxCountOfVisibleItems - 1),
24323b3eb3cSopenharmony_ci              (item:ComposeTitleBarMenuItem, index:number) => {
24423b3eb3cSopenharmony_ci                ImageMenuItem({ item: item, index: this.index * 1000 + index + 1 })
24523b3eb3cSopenharmony_ci              })
24623b3eb3cSopenharmony_ci
24723b3eb3cSopenharmony_ci            Row() {
24823b3eb3cSopenharmony_ci              Image(PUBLIC_MORE)
24923b3eb3cSopenharmony_ci                .width(ImageMenuItem.imageSize)
25023b3eb3cSopenharmony_ci                .draggable(false)
25123b3eb3cSopenharmony_ci                .height(ImageMenuItem.imageSize)
25223b3eb3cSopenharmony_ci                .fillColor($r('sys.color.icon_primary'))
25323b3eb3cSopenharmony_ci                .focusable(true)
25423b3eb3cSopenharmony_ci            }
25523b3eb3cSopenharmony_ci            .width(ImageMenuItem.imageHotZoneWidth)
25623b3eb3cSopenharmony_ci            .height(ImageMenuItem.imageHotZoneWidth)
25723b3eb3cSopenharmony_ci            .borderRadius(ImageMenuItem.buttonBorderRadius)
25823b3eb3cSopenharmony_ci            .foregroundColor(this.getMoreIconFgColor())
25923b3eb3cSopenharmony_ci            .backgroundColor(this.getMoreIconBgColor())
26023b3eb3cSopenharmony_ci            .justifyContent(FlexAlign.Center)
26123b3eb3cSopenharmony_ci            .stateStyles({
26223b3eb3cSopenharmony_ci              focused: {
26323b3eb3cSopenharmony_ci                .border({
26423b3eb3cSopenharmony_ci                  radius: $r('sys.float.ohos_id_corner_radius_clicked'),
26523b3eb3cSopenharmony_ci                  width: ImageMenuItem.focusBorderWidth,
26623b3eb3cSopenharmony_ci                  color: $r('sys.color.ohos_id_color_focused_outline'),
26723b3eb3cSopenharmony_ci                  style: BorderStyle.Solid
26823b3eb3cSopenharmony_ci                })
26923b3eb3cSopenharmony_ci              },
27023b3eb3cSopenharmony_ci              normal: {
27123b3eb3cSopenharmony_ci                .border({
27223b3eb3cSopenharmony_ci                  radius: $r('sys.float.ohos_id_corner_radius_clicked'),
27323b3eb3cSopenharmony_ci                  width: 0
27423b3eb3cSopenharmony_ci                })
27523b3eb3cSopenharmony_ci              }
27623b3eb3cSopenharmony_ci            })
27723b3eb3cSopenharmony_ci            .onFocus(() => this.isMoreIconOnFocus = true)
27823b3eb3cSopenharmony_ci            .onBlur(() => this.isMoreIconOnFocus = false)
27923b3eb3cSopenharmony_ci            .onHover((isOn) => this.isMoreIconOnHover = isOn)
28023b3eb3cSopenharmony_ci            .onKeyEvent((event) => {
28123b3eb3cSopenharmony_ci              if (event.keyCode !== KeyCode.KEYCODE_ENTER &&
28223b3eb3cSopenharmony_ci                event.keyCode !== KeyCode.KEYCODE_SPACE) {
28323b3eb3cSopenharmony_ci                return
28423b3eb3cSopenharmony_ci              }
28523b3eb3cSopenharmony_ci              if (event.type === KeyType.Down) {
28623b3eb3cSopenharmony_ci                this.isMoreIconOnClick = true
28723b3eb3cSopenharmony_ci              }
28823b3eb3cSopenharmony_ci              if (event.type === KeyType.Up) {
28923b3eb3cSopenharmony_ci                this.isMoreIconOnClick = false
29023b3eb3cSopenharmony_ci              }
29123b3eb3cSopenharmony_ci            })
29223b3eb3cSopenharmony_ci            .onTouch((event) => {
29323b3eb3cSopenharmony_ci              if (event.type === TouchType.Down) {
29423b3eb3cSopenharmony_ci                this.isMoreIconOnClick = true
29523b3eb3cSopenharmony_ci              }
29623b3eb3cSopenharmony_ci              if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
29723b3eb3cSopenharmony_ci                this.isMoreIconOnClick = false
29823b3eb3cSopenharmony_ci                if (this.fontSize >= this.minFontSize) {
29923b3eb3cSopenharmony_ci                  this.dialogController?.close()
30023b3eb3cSopenharmony_ci                }
30123b3eb3cSopenharmony_ci              }
30223b3eb3cSopenharmony_ci            })
30323b3eb3cSopenharmony_ci            .onClick(() => this.isPopupShown = true)
30423b3eb3cSopenharmony_ci            .gesture(
30523b3eb3cSopenharmony_ci              LongPressGesture({ repeat: false, duration: this.longPressTime })
30623b3eb3cSopenharmony_ci                .onAction((event: GestureEvent) => {
30723b3eb3cSopenharmony_ci                  this.fontSize = this.decideFontScale();
30823b3eb3cSopenharmony_ci                  if (event) {
30923b3eb3cSopenharmony_ci                    if (this.fontSize >= this.minFontSize) {
31023b3eb3cSopenharmony_ci                      this.dialogController?.open()
31123b3eb3cSopenharmony_ci                    }
31223b3eb3cSopenharmony_ci                  }
31323b3eb3cSopenharmony_ci                }))
31423b3eb3cSopenharmony_ci            .bindPopup(this.isPopupShown, {
31523b3eb3cSopenharmony_ci              builder: this.popupBuilder,
31623b3eb3cSopenharmony_ci              placement: Placement.Bottom,
31723b3eb3cSopenharmony_ci              popupColor: Color.White,
31823b3eb3cSopenharmony_ci              enableArrow: false,
31923b3eb3cSopenharmony_ci              onStateChange: (e) => {
32023b3eb3cSopenharmony_ci                this.isPopupShown = e.isVisible
32123b3eb3cSopenharmony_ci                if (!e.isVisible) {
32223b3eb3cSopenharmony_ci                  this.isMoreIconOnClick = false
32323b3eb3cSopenharmony_ci                }
32423b3eb3cSopenharmony_ci              }
32523b3eb3cSopenharmony_ci            })
32623b3eb3cSopenharmony_ci          }
32723b3eb3cSopenharmony_ci        }
32823b3eb3cSopenharmony_ci      }
32923b3eb3cSopenharmony_ci    }
33023b3eb3cSopenharmony_ci    .height('100%')
33123b3eb3cSopenharmony_ci    .margin({ right: $r('sys.float.ohos_id_default_padding_end') })
33223b3eb3cSopenharmony_ci    .justifyContent(FlexAlign.Center)
33323b3eb3cSopenharmony_ci  }
33423b3eb3cSopenharmony_ci
33523b3eb3cSopenharmony_ci  @Builder
33623b3eb3cSopenharmony_ci  popupBuilder() {
33723b3eb3cSopenharmony_ci    Column() {
33823b3eb3cSopenharmony_ci      if (this.menuItems) {
33923b3eb3cSopenharmony_ci        ForEach(this.menuItems.slice(CollapsibleMenuSection.maxCountOfVisibleItems - 1,
34023b3eb3cSopenharmony_ci          this.menuItems.length),
34123b3eb3cSopenharmony_ci          (item:ComposeTitleBarMenuItem, index:number) => {
34223b3eb3cSopenharmony_ci            ImageMenuItem({ item: item, index: this.index * 1000 +
34323b3eb3cSopenharmony_ci            CollapsibleMenuSection.maxCountOfVisibleItems + index, isPopup: true })
34423b3eb3cSopenharmony_ci          })
34523b3eb3cSopenharmony_ci      }
34623b3eb3cSopenharmony_ci    }
34723b3eb3cSopenharmony_ci    .width(ImageMenuItem.imageHotZoneWidth +
34823b3eb3cSopenharmony_ci      CollapsibleMenuSection.focusPadding * CollapsibleMenuSection.marginsNum)
34923b3eb3cSopenharmony_ci    .margin({ top: CollapsibleMenuSection.focusPadding, bottom: CollapsibleMenuSection.focusPadding })
35023b3eb3cSopenharmony_ci    .onAppear(() => {
35123b3eb3cSopenharmony_ci      focusControl.requestFocus(ImageMenuItem.focusablePrefix +
35223b3eb3cSopenharmony_ci      this.firstFocusableIndex)
35323b3eb3cSopenharmony_ci    })
35423b3eb3cSopenharmony_ci  }
35523b3eb3cSopenharmony_ci}
35623b3eb3cSopenharmony_ci
35723b3eb3cSopenharmony_ci@Component
35823b3eb3cSopenharmony_cistruct ImageMenuItem {
35923b3eb3cSopenharmony_ci  item: ComposeTitleBarMenuItem = {} as ComposeTitleBarMenuItem;
36023b3eb3cSopenharmony_ci  index: number = 0
36123b3eb3cSopenharmony_ci  longPressTime: number = 500;
36223b3eb3cSopenharmony_ci  minFontSize: number = 1.75;
36323b3eb3cSopenharmony_ci  isFollowingSystemFontScale: boolean = false;
36423b3eb3cSopenharmony_ci  maxFontScale: number = 1;
36523b3eb3cSopenharmony_ci  systemFontScale?: number = 1;
36623b3eb3cSopenharmony_ci  isPopup: boolean = false;
36723b3eb3cSopenharmony_ci
36823b3eb3cSopenharmony_ci  static readonly imageSize = 24
36923b3eb3cSopenharmony_ci  static readonly imageHotZoneWidth = 48
37023b3eb3cSopenharmony_ci  static readonly buttonBorderRadius = 8
37123b3eb3cSopenharmony_ci  static readonly focusBorderWidth = 2
37223b3eb3cSopenharmony_ci  static readonly disabledImageOpacity = 0.4
37323b3eb3cSopenharmony_ci  static readonly focusablePrefix = "Id-ComposeTitleBar-ImageMenuItem-"
37423b3eb3cSopenharmony_ci
37523b3eb3cSopenharmony_ci  @State isOnFocus: boolean = false
37623b3eb3cSopenharmony_ci  @State isOnHover: boolean = false
37723b3eb3cSopenharmony_ci  @State isOnClick: boolean = false
37823b3eb3cSopenharmony_ci  @Prop fontSize: number = 1
37923b3eb3cSopenharmony_ci
38023b3eb3cSopenharmony_ci  dialogController: CustomDialogController | null = new CustomDialogController({
38123b3eb3cSopenharmony_ci    builder: ComposeTitleBarDialog({
38223b3eb3cSopenharmony_ci      cancel: () => {
38323b3eb3cSopenharmony_ci      },
38423b3eb3cSopenharmony_ci      confirm: () => {
38523b3eb3cSopenharmony_ci      },
38623b3eb3cSopenharmony_ci      itemComposeTitleDialog: this.item,
38723b3eb3cSopenharmony_ci      composeTitleBarDialog: this.item.label ? this.item.label : this.textDialog(),
38823b3eb3cSopenharmony_ci      fontSize: this.fontSize,
38923b3eb3cSopenharmony_ci    }),
39023b3eb3cSopenharmony_ci    maskColor: Color.Transparent,
39123b3eb3cSopenharmony_ci    isModal: true,
39223b3eb3cSopenharmony_ci    customStyle: true,
39323b3eb3cSopenharmony_ci  })
39423b3eb3cSopenharmony_ci
39523b3eb3cSopenharmony_ci  private textDialog(): ResourceStr {
39623b3eb3cSopenharmony_ci    if (this.item.value === PUBLIC_MORE) {
39723b3eb3cSopenharmony_ci      return $r('sys.string.ohos_toolbar_more');
39823b3eb3cSopenharmony_ci    } else if (this.item.value === PUBLIC_BACK) {
39923b3eb3cSopenharmony_ci      return $r('sys.string.icon_back');
40023b3eb3cSopenharmony_ci    } else {
40123b3eb3cSopenharmony_ci      return this.item.label ? this.item.label : '';
40223b3eb3cSopenharmony_ci    }
40323b3eb3cSopenharmony_ci  }
40423b3eb3cSopenharmony_ci
40523b3eb3cSopenharmony_ci  getFgColor() {
40623b3eb3cSopenharmony_ci    return this.isOnClick
40723b3eb3cSopenharmony_ci      ? $r('sys.color.ohos_id_color_titlebar_icon_pressed')
40823b3eb3cSopenharmony_ci      : $r('sys.color.ohos_id_color_titlebar_icon')
40923b3eb3cSopenharmony_ci  }
41023b3eb3cSopenharmony_ci
41123b3eb3cSopenharmony_ci  getBgColor() {
41223b3eb3cSopenharmony_ci    if (this.isOnClick) {
41323b3eb3cSopenharmony_ci      return $r('sys.color.ohos_id_color_click_effect')
41423b3eb3cSopenharmony_ci    } else if (this.isOnHover) {
41523b3eb3cSopenharmony_ci      return $r('sys.color.ohos_id_color_hover')
41623b3eb3cSopenharmony_ci    } else {
41723b3eb3cSopenharmony_ci      return Color.Transparent
41823b3eb3cSopenharmony_ci    }
41923b3eb3cSopenharmony_ci  }
42023b3eb3cSopenharmony_ci
42123b3eb3cSopenharmony_ci  aboutToAppear() {
42223b3eb3cSopenharmony_ci    try {
42323b3eb3cSopenharmony_ci      let uiContent: UIContext = this.getUIContext();
42423b3eb3cSopenharmony_ci      this.isFollowingSystemFontScale = uiContent.isFollowingSystemFontScale();
42523b3eb3cSopenharmony_ci      this.maxFontScale = uiContent.getMaxFontScale();
42623b3eb3cSopenharmony_ci    } catch (err) {
42723b3eb3cSopenharmony_ci      let code: number = (err as BusinessError).code;
42823b3eb3cSopenharmony_ci      let message: string = (err as BusinessError).message;
42923b3eb3cSopenharmony_ci      hilog.error(0x3900, 'ComposeTitleBar', `Failed to init fontsizescale info, cause, code: ${code}, message: ${message}`);
43023b3eb3cSopenharmony_ci    }
43123b3eb3cSopenharmony_ci  }
43223b3eb3cSopenharmony_ci
43323b3eb3cSopenharmony_ci
43423b3eb3cSopenharmony_ci  decideFontScale(): number {
43523b3eb3cSopenharmony_ci    try {
43623b3eb3cSopenharmony_ci      let uiContent: UIContext = this.getUIContext();
43723b3eb3cSopenharmony_ci      this.systemFontScale = (uiContent.getHostContext() as common.UIAbilityContext)?.config?.fontSizeScale ?? 1;
43823b3eb3cSopenharmony_ci      if (!this.isFollowingSystemFontScale) {
43923b3eb3cSopenharmony_ci        return 1;
44023b3eb3cSopenharmony_ci      }
44123b3eb3cSopenharmony_ci      return Math.min(this.systemFontScale, this.maxFontScale);
44223b3eb3cSopenharmony_ci    } catch (exception) {
44323b3eb3cSopenharmony_ci      let code: number = (exception as BusinessError).code;
44423b3eb3cSopenharmony_ci      let message: string = (exception as BusinessError).message;
44523b3eb3cSopenharmony_ci      hilog.error(0x3900, 'ComposeTitleBar', `Faild to decideFontScale,cause, code: ${code}, message: ${message}`);
44623b3eb3cSopenharmony_ci      return 1;
44723b3eb3cSopenharmony_ci    }
44823b3eb3cSopenharmony_ci  }
44923b3eb3cSopenharmony_ci
45023b3eb3cSopenharmony_ci
45123b3eb3cSopenharmony_ci  build() {
45223b3eb3cSopenharmony_ci    Row() {
45323b3eb3cSopenharmony_ci      Image(this.item?.value)
45423b3eb3cSopenharmony_ci        .matchTextDirection(this.item?.value === PUBLIC_BACK ? true : false)
45523b3eb3cSopenharmony_ci        .width(ImageMenuItem.imageSize)
45623b3eb3cSopenharmony_ci        .draggable(false)
45723b3eb3cSopenharmony_ci        .height(ImageMenuItem.imageSize)
45823b3eb3cSopenharmony_ci        .focusable(this.item?.isEnabled)
45923b3eb3cSopenharmony_ci        .key(ImageMenuItem.focusablePrefix + this.index)
46023b3eb3cSopenharmony_ci        .fillColor($r('sys.color.ohos_id_color_text_primary'))
46123b3eb3cSopenharmony_ci    }
46223b3eb3cSopenharmony_ci    .width(ImageMenuItem.imageHotZoneWidth)
46323b3eb3cSopenharmony_ci    .height(ImageMenuItem.imageHotZoneWidth)
46423b3eb3cSopenharmony_ci    .borderRadius(ImageMenuItem.buttonBorderRadius)
46523b3eb3cSopenharmony_ci    .foregroundColor(this.getFgColor())
46623b3eb3cSopenharmony_ci    .backgroundColor(this.getBgColor())
46723b3eb3cSopenharmony_ci    .justifyContent(FlexAlign.Center)
46823b3eb3cSopenharmony_ci    .opacity(this.item?.isEnabled ? 1 : ImageMenuItem.disabledImageOpacity)
46923b3eb3cSopenharmony_ci    .stateStyles({
47023b3eb3cSopenharmony_ci      focused: {
47123b3eb3cSopenharmony_ci        .border({
47223b3eb3cSopenharmony_ci          radius: $r('sys.float.ohos_id_corner_radius_clicked'),
47323b3eb3cSopenharmony_ci          width: ImageMenuItem.focusBorderWidth,
47423b3eb3cSopenharmony_ci          color: $r('sys.color.ohos_id_color_focused_outline'),
47523b3eb3cSopenharmony_ci          style: BorderStyle.Solid
47623b3eb3cSopenharmony_ci        })
47723b3eb3cSopenharmony_ci      },
47823b3eb3cSopenharmony_ci      normal: {
47923b3eb3cSopenharmony_ci        .border({
48023b3eb3cSopenharmony_ci          radius: $r('sys.float.ohos_id_corner_radius_clicked'),
48123b3eb3cSopenharmony_ci          width: 0
48223b3eb3cSopenharmony_ci        })
48323b3eb3cSopenharmony_ci      }
48423b3eb3cSopenharmony_ci    })
48523b3eb3cSopenharmony_ci    .onFocus(() => {
48623b3eb3cSopenharmony_ci      if (!this.item?.isEnabled) {
48723b3eb3cSopenharmony_ci        return
48823b3eb3cSopenharmony_ci      }
48923b3eb3cSopenharmony_ci      this.isOnFocus = true
49023b3eb3cSopenharmony_ci    })
49123b3eb3cSopenharmony_ci    .onBlur(() => this.isOnFocus = false)
49223b3eb3cSopenharmony_ci    .onHover((isOn) => {
49323b3eb3cSopenharmony_ci      if (!this.item?.isEnabled) {
49423b3eb3cSopenharmony_ci        return
49523b3eb3cSopenharmony_ci      }
49623b3eb3cSopenharmony_ci      this.isOnHover = isOn
49723b3eb3cSopenharmony_ci    })
49823b3eb3cSopenharmony_ci    .onKeyEvent((event) => {
49923b3eb3cSopenharmony_ci      if (!this.item?.isEnabled) {
50023b3eb3cSopenharmony_ci        return
50123b3eb3cSopenharmony_ci      }
50223b3eb3cSopenharmony_ci      if (event.keyCode !== KeyCode.KEYCODE_ENTER &&
50323b3eb3cSopenharmony_ci        event.keyCode !== KeyCode.KEYCODE_SPACE) {
50423b3eb3cSopenharmony_ci        return
50523b3eb3cSopenharmony_ci      }
50623b3eb3cSopenharmony_ci      if (event.type === KeyType.Down) {
50723b3eb3cSopenharmony_ci        this.isOnClick = true
50823b3eb3cSopenharmony_ci      }
50923b3eb3cSopenharmony_ci      if (event.type === KeyType.Up) {
51023b3eb3cSopenharmony_ci        this.isOnClick = false
51123b3eb3cSopenharmony_ci      }
51223b3eb3cSopenharmony_ci    })
51323b3eb3cSopenharmony_ci    .onTouch((event) => {
51423b3eb3cSopenharmony_ci      if (!this.item?.isEnabled) {
51523b3eb3cSopenharmony_ci        return
51623b3eb3cSopenharmony_ci      }
51723b3eb3cSopenharmony_ci      if (event.type === TouchType.Down) {
51823b3eb3cSopenharmony_ci        this.isOnClick = true
51923b3eb3cSopenharmony_ci      }
52023b3eb3cSopenharmony_ci      if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
52123b3eb3cSopenharmony_ci        this.isOnClick = false
52223b3eb3cSopenharmony_ci        if (this.fontSize >= this.minFontSize && this.isPopup === false) {
52323b3eb3cSopenharmony_ci          this.dialogController?.close()
52423b3eb3cSopenharmony_ci        }
52523b3eb3cSopenharmony_ci      }
52623b3eb3cSopenharmony_ci    })
52723b3eb3cSopenharmony_ci    .onClick(() => {
52823b3eb3cSopenharmony_ci      if (this.item) {
52923b3eb3cSopenharmony_ci        return this.item.isEnabled && this.item.action?.()
53023b3eb3cSopenharmony_ci      }
53123b3eb3cSopenharmony_ci    })
53223b3eb3cSopenharmony_ci    .gesture(
53323b3eb3cSopenharmony_ci      LongPressGesture({ repeat: false, duration: this.longPressTime })
53423b3eb3cSopenharmony_ci        .onAction((event: GestureEvent) => {
53523b3eb3cSopenharmony_ci          this.fontSize = this.decideFontScale();
53623b3eb3cSopenharmony_ci          if (event) {
53723b3eb3cSopenharmony_ci            if (this.fontSize >= this.minFontSize && this.isPopup === false) {
53823b3eb3cSopenharmony_ci              this.dialogController?.open()
53923b3eb3cSopenharmony_ci            }
54023b3eb3cSopenharmony_ci          }
54123b3eb3cSopenharmony_ci        }))
54223b3eb3cSopenharmony_ci  }
54323b3eb3cSopenharmony_ci}
54423b3eb3cSopenharmony_ci
54523b3eb3cSopenharmony_ci
54623b3eb3cSopenharmony_ci/**
54723b3eb3cSopenharmony_ci *  ComposeTitleBarDialog
54823b3eb3cSopenharmony_ci */
54923b3eb3cSopenharmony_ci@CustomDialog
55023b3eb3cSopenharmony_cistruct ComposeTitleBarDialog {
55123b3eb3cSopenharmony_ci  itemComposeTitleDialog: ComposeTitleBarMenuItem = {} as ComposeTitleBarMenuItem;
55223b3eb3cSopenharmony_ci  callbackId: number | undefined = undefined;
55323b3eb3cSopenharmony_ci  composeTitleBarDialog?: ResourceStr = '';
55423b3eb3cSopenharmony_ci  mainWindowStage: window.Window | undefined = undefined;
55523b3eb3cSopenharmony_ci  controller?: CustomDialogController;
55623b3eb3cSopenharmony_ci  minFontSize: number = 1.75;
55723b3eb3cSopenharmony_ci  maxFontSize: number = 3.2;
55823b3eb3cSopenharmony_ci  screenWidth: number = 640;
55923b3eb3cSopenharmony_ci  verticalScreenLines: number = 6;
56023b3eb3cSopenharmony_ci  horizontalsScreenLines: number = 1;
56123b3eb3cSopenharmony_ci  @StorageLink('mainWindow') mainWindow: Promise<window.Window> | undefined = undefined;
56223b3eb3cSopenharmony_ci  @State fontSize: number = 1;
56323b3eb3cSopenharmony_ci  @State maxLines: number = 1;
56423b3eb3cSopenharmony_ci  @StorageProp('windowStandardHeight') windowStandardHeight: number = 0;
56523b3eb3cSopenharmony_ci  cancel: () => void = () => {
56623b3eb3cSopenharmony_ci  }
56723b3eb3cSopenharmony_ci  confirm: () => void = () => {
56823b3eb3cSopenharmony_ci  }
56923b3eb3cSopenharmony_ci
57023b3eb3cSopenharmony_ci  build() {
57123b3eb3cSopenharmony_ci    if (this.composeTitleBarDialog) {
57223b3eb3cSopenharmony_ci      Column() {
57323b3eb3cSopenharmony_ci        Image(this.itemComposeTitleDialog.value)
57423b3eb3cSopenharmony_ci          .width(IMAGE_SIZE)
57523b3eb3cSopenharmony_ci          .height(IMAGE_SIZE)
57623b3eb3cSopenharmony_ci          .margin({
57723b3eb3cSopenharmony_ci            top: $r('sys.float.padding_level24'),
57823b3eb3cSopenharmony_ci            bottom: $r('sys.float.padding_level8'),
57923b3eb3cSopenharmony_ci          })
58023b3eb3cSopenharmony_ci          .fillColor($r('sys.color.icon_primary'))
58123b3eb3cSopenharmony_ci        Column() {
58223b3eb3cSopenharmony_ci          Text(this.composeTitleBarDialog)
58323b3eb3cSopenharmony_ci            .fontSize(TEXT_EDITABLE_DIALOG)
58423b3eb3cSopenharmony_ci            .textOverflow({ overflow: TextOverflow.Ellipsis })
58523b3eb3cSopenharmony_ci            .maxLines(this.maxLines)
58623b3eb3cSopenharmony_ci            .width('100%')
58723b3eb3cSopenharmony_ci            .textAlign(TextAlign.Center)
58823b3eb3cSopenharmony_ci            .fontColor($r('sys.color.font_primary'))
58923b3eb3cSopenharmony_ci        }
59023b3eb3cSopenharmony_ci        .width('100%')
59123b3eb3cSopenharmony_ci        .padding({
59223b3eb3cSopenharmony_ci          left: $r('sys.float.padding_level4'),
59323b3eb3cSopenharmony_ci          right: $r('sys.float.padding_level4'),
59423b3eb3cSopenharmony_ci          bottom: $r('sys.float.padding_level12'),
59523b3eb3cSopenharmony_ci        })
59623b3eb3cSopenharmony_ci      }
59723b3eb3cSopenharmony_ci      .width(this.fontSize === this.maxFontSize ? MAX_DIALOG : MIN_DIALOG)
59823b3eb3cSopenharmony_ci      .constraintSize({ minHeight: this.fontSize === this.maxFontSize ? MAX_DIALOG : MIN_DIALOG })
59923b3eb3cSopenharmony_ci      .backgroundBlurStyle(BlurStyle.COMPONENT_ULTRA_THICK)
60023b3eb3cSopenharmony_ci      .shadow(ShadowStyle.OUTER_DEFAULT_LG)
60123b3eb3cSopenharmony_ci      .borderRadius($r('sys.float.corner_radius_level10'))
60223b3eb3cSopenharmony_ci    } else {
60323b3eb3cSopenharmony_ci      Column() {
60423b3eb3cSopenharmony_ci        Image(this.itemComposeTitleDialog.value)
60523b3eb3cSopenharmony_ci          .width(IMAGE_SIZE)
60623b3eb3cSopenharmony_ci          .height(IMAGE_SIZE)
60723b3eb3cSopenharmony_ci          .fillColor($r('sys.color.icon_primary'))
60823b3eb3cSopenharmony_ci      }
60923b3eb3cSopenharmony_ci      .width(this.fontSize === this.maxFontSize ? MAX_DIALOG : MIN_DIALOG)
61023b3eb3cSopenharmony_ci      .constraintSize({ minHeight: this.fontSize === this.maxFontSize ? MAX_DIALOG : MIN_DIALOG })
61123b3eb3cSopenharmony_ci      .backgroundBlurStyle(BlurStyle.COMPONENT_ULTRA_THICK)
61223b3eb3cSopenharmony_ci      .shadow(ShadowStyle.OUTER_DEFAULT_LG)
61323b3eb3cSopenharmony_ci      .borderRadius($r('sys.float.corner_radius_level10'))
61423b3eb3cSopenharmony_ci      .justifyContent(FlexAlign.Center)
61523b3eb3cSopenharmony_ci    }
61623b3eb3cSopenharmony_ci  }
61723b3eb3cSopenharmony_ci
61823b3eb3cSopenharmony_ci  async aboutToAppear(): Promise<void> {
61923b3eb3cSopenharmony_ci    let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
62023b3eb3cSopenharmony_ci    this.mainWindowStage = context.windowStage.getMainWindowSync();
62123b3eb3cSopenharmony_ci    let properties: window.WindowProperties = this.mainWindowStage.getWindowProperties();
62223b3eb3cSopenharmony_ci    let rect = properties.windowRect;
62323b3eb3cSopenharmony_ci    if (px2vp(rect.height) > this.screenWidth) {
62423b3eb3cSopenharmony_ci      this.maxLines = this.verticalScreenLines;
62523b3eb3cSopenharmony_ci    } else {
62623b3eb3cSopenharmony_ci      this.maxLines = this.horizontalsScreenLines;
62723b3eb3cSopenharmony_ci    }
62823b3eb3cSopenharmony_ci  }
62923b3eb3cSopenharmony_ci}
63023b3eb3cSopenharmony_ci
63123b3eb3cSopenharmony_ciexport { ComposeTitleBar }