• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023-2023 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 { KeyCode } from '@ohos.multimodalInput.keyCode'
17
18const SPACE_MARGIN: number = 8
19const MARGIN_NUM: number = 4
20const IMAGE_WIDTH_NUM: number = 16
21const IMAGE_HEIGHT_NUM: number = 24
22const BUTTON_SIZE: number = 32
23const SINGLE_LINE_HEIGHT: number = 48
24const DOUBLE_LINE_HEIGHT: number = 64
25const BUTTON_HEIGHT: number = 28
26const IMAGE_WIDTH: number = 12
27const BORDER_WIDTH = 2
28const DIVIDEND_WIDTH = 3
29const SINGLE_LINE_NUM: number = 1
30const DOUBLE_LINE_NUM: number = 2
31const MIN_FONT_SIZE: number = 14
32const MAIN_TEXT_SIZE: number = 10
33const CONSTRAINT_NUM: number = 44
34const CONTENT_NUM: number = 40
35
36export enum OperationType {
37  TEXT_ARROW = 0,
38  BUTTON = 1,
39  ICON_GROUP = 2,
40  LOADING = 3,
41}
42
43export declare type OperationOption = {
44  value: ResourceStr;
45  action?: () => void;
46}
47
48export declare type SelectOptions = {
49  options: Array<SelectOption>;
50  selected?: number;
51  value?: string;
52  onSelect?: (index: number, value?: string) => void;
53}
54
55@Component
56struct IconGroup {
57  @State bgColor: Resource = $r('sys.color.ohos_id_color_sub_background_transparent')
58  @State isFocus: boolean = false
59  item: OperationOption
60  focusBorderWidth = BORDER_WIDTH
61
62  build() {
63    Row() {
64      Image(this.item.value)
65        .fillColor($r('sys.color.ohos_id_color_primary'))
66        .width(IMAGE_HEIGHT_NUM)
67        .height(IMAGE_HEIGHT_NUM)
68        .focusable(true)
69    }
70    .focusable(true)
71    .width(BUTTON_SIZE)
72    .height(BUTTON_SIZE)
73    .margin({ right: SPACE_MARGIN, bottom: MARGIN_NUM })
74    .justifyContent(FlexAlign.Center)
75    .borderRadius($r('sys.float.ohos_id_corner_radius_clicked'))
76    .backgroundColor(this.bgColor)
77    .onTouch((event) => {
78      if (event.type === TouchType.Down) {
79        this.item.action && this.item.action()
80        this.bgColor = $r('sys.color.ohos_id_color_click_effect')
81      }
82      if (event.type === TouchType.Up) {
83        this.bgColor = $r('sys.color.ohos_id_color_sub_background_transparent')
84      }
85    })
86    .onHover((isHover: boolean) => {
87      if (isHover) {
88        this.bgColor = $r('sys.color.ohos_id_color_hover')
89      } else {
90        this.bgColor = $r('sys.color.ohos_id_color_sub_background_transparent')
91      }
92    })
93    .stateStyles({
94      focused: {
95        .border({
96          radius: $r('sys.float.ohos_id_corner_radius_clicked'),
97          width: this.focusBorderWidth,
98          color: $r('sys.color.ohos_id_color_focused_outline'),
99          style: BorderStyle.Solid
100        })
101      },
102      normal: {
103        .border({
104          radius: $r('sys.float.ohos_id_corner_radius_clicked'),
105          width: 0 })
106      }
107    })
108    .onKeyEvent((event) => {
109      if (event.keyCode === KeyCode.KEYCODE_ENTER || event.keyCode === KeyCode.KEYCODE_SPACE) {
110        this.item.action && this.item.action()
111      }
112    })
113  }
114}
115
116@Component
117export struct SubHeader {
118  @Prop icon: Resource
119  @Prop primaryTitle: string
120  @Prop secondaryTitle: string
121  @Prop select: SelectOptions
122  @Prop operationType: OperationType = OperationType.BUTTON
123  operationItem: Array<OperationOption>
124  @State isDuplicateLine: boolean = false
125  @State textArrowBgColor: Resource = $r('sys.color.ohos_id_color_sub_background_transparent')
126  @State buttonBgColor: Resource = $r('sys.color.ohos_id_color_sub_background_transparent')
127  @State flexWidth: number = 0
128  @State textArrowWidth: number = 0
129  @State textArrowFocus: boolean = false
130  @State buttonFocus: boolean = false
131  @State arrowWidth: number = 0
132  @State buttonWidth: number = 0
133  focusBorderWidth = BORDER_WIDTH
134
135  @Builder ListTextStyle($$: { content: ResourceStr }) {
136    Text($$.content)
137      .fontColor($r('sys.color.ohos_id_color_text_secondary'))
138      .fontSize($r('sys.float.ohos_id_text_size_sub_title3'))
139      .fontWeight(FontWeight.Medium)
140      .maxLines(DOUBLE_LINE_NUM)
141      .textOverflow({ overflow: TextOverflow.Ellipsis })
142      .margin({ left: $r('sys.float.ohos_id_max_padding_end'), bottom: SPACE_MARGIN, right: MARGIN_NUM })
143  }
144
145  @Builder ListIconStyle($$: { content: ResourceStr }, icon: ResourceStr) {
146    Row() {
147      Image(icon)
148        .width(IMAGE_WIDTH_NUM)
149        .height(IMAGE_WIDTH_NUM)
150        .margin({ right: SPACE_MARGIN })
151      Text($$.content)
152        .fontColor($r('sys.color.ohos_id_color_text_secondary'))
153        .fontSize($r('sys.float.ohos_id_text_size_sub_title3'))
154        .fontWeight(FontWeight.Medium)
155        .maxLines(DOUBLE_LINE_NUM)
156        .textOverflow({ overflow: TextOverflow.Ellipsis })
157    }
158    .margin({ left: $r('sys.float.ohos_id_max_padding_end'), bottom: SPACE_MARGIN, right: MARGIN_NUM })
159  }
160
161  @Builder ContentTextStyle($$: { content: ResourceStr }) {
162    Text($$.content)
163      .fontColor($r('sys.color.ohos_id_color_text_primary'))
164      .fontSize($r('sys.float.ohos_id_text_size_sub_title1'))
165      .fontWeight(FontWeight.Medium)
166      .maxLines(DOUBLE_LINE_NUM)
167      .maxFontSize($r('sys.float.ohos_id_text_size_sub_title1'))
168      .minFontSize(MIN_FONT_SIZE)
169      .textOverflow({ overflow: TextOverflow.Ellipsis })
170      .margin({ left: $r('sys.float.ohos_id_max_padding_start'),
171        right: MARGIN_NUM, bottom: SPACE_MARGIN })
172  }
173
174  @Builder SubTextStyle($$: { content: ResourceStr, subContent: ResourceStr }) {
175    Column() {
176      Text($$.content)
177        .fontColor($r('sys.color.ohos_id_color_text_primary'))
178        .fontSize($r('sys.float.ohos_id_text_size_sub_title1'))
179        .fontWeight(FontWeight.Medium)
180        .maxLines(SINGLE_LINE_NUM)
181        .maxFontSize($r('sys.float.ohos_id_text_size_sub_title1'))
182        .minFontSize(MIN_FONT_SIZE)
183        .textOverflow({ overflow: TextOverflow.Ellipsis })
184      Text($$.subContent)
185        .fontColor($r('sys.color.ohos_id_color_text_secondary'))
186        .fontSize($r('sys.float.ohos_id_text_size_sub_title3'))
187        .fontWeight(FontWeight.Medium)
188        .maxLines(SINGLE_LINE_NUM)
189        .maxFontSize($r('sys.float.ohos_id_text_size_sub_title3'))
190        .minFontSize(MAIN_TEXT_SIZE)
191        .textOverflow({ overflow: TextOverflow.Ellipsis })
192    }
193    .alignItems(HorizontalAlign.Start)
194    .onAppear(() => {
195      this.isDuplicateLine = true
196    })
197    .margin({ left: $r('sys.float.ohos_id_max_padding_start'),
198      right: MARGIN_NUM, bottom: SPACE_MARGIN })
199  }
200
201  @Builder SelectStyle(selectParam: SelectOptions) {
202    Select(selectParam.options)
203      .selected(selectParam.selected)
204      .value(selectParam.value)
205      .onSelect((index: number, value?: string) => {
206        if (selectParam.onSelect) {
207          selectParam.onSelect(index, value)
208        }
209      })
210      .font({
211        size: $r('sys.float.ohos_id_text_size_sub_title1'),
212        weight: FontWeight.Medium
213      })
214      .margin({ left: $r('sys.float.ohos_id_default_padding_start'), right: MARGIN_NUM })
215  }
216
217  @Builder LoadingProcessStyle() {
218    LoadingProgress()
219      .width(IMAGE_HEIGHT_NUM)
220      .height(IMAGE_HEIGHT_NUM)
221      .focusable(true)
222      .margin({ right: $r('sys.float.ohos_id_default_padding_end'), bottom: MARGIN_NUM })
223  }
224
225  @Builder TextArrowStyle(textArrow: OperationOption) {
226    Row() {
227      Stack() {
228        Row() {
229          Row() {
230            if (textArrow != null) {
231              Text(textArrow.value)
232                .fontColor($r('sys.color.ohos_id_color_text_secondary'))
233                .fontSize($r('sys.float.ohos_id_text_size_body2'))
234                .margin({ right: MARGIN_NUM })
235                .focusable(true)
236                .maxLines(1)
237                .constraintSize({ maxWidth: this.textArrowWidth - CONTENT_NUM })
238            }
239            Image($r('sys.media.ohos_ic_public_arrow_right'))
240              .fillColor($r('sys.color.ohos_id_color_tertiary'))
241              .width(IMAGE_WIDTH)
242              .height(IMAGE_HEIGHT_NUM)
243              .focusable(true)
244          }.margin({ left: SPACE_MARGIN, right: SPACE_MARGIN })
245        }
246        .height(BUTTON_SIZE)
247        .justifyContent(FlexAlign.End)
248        .onFocus(() => {
249          this.textArrowFocus = true
250        })
251        .onBlur(() => {
252          this.textArrowFocus = false
253        })
254        .borderRadius(MARGIN_NUM)
255        .focusable(true)
256        .margin({ left: MARGIN_NUM, right: MARGIN_NUM })
257        .backgroundColor(this.textArrowBgColor)
258        .onTouch((event) => {
259          if (event.type === TouchType.Down) {
260            if (textArrow.action) {
261              textArrow.action()
262            }
263            this.textArrowBgColor = $r('sys.color.ohos_id_color_click_effect')
264          }
265          if (event.type === TouchType.Up) {
266            this.textArrowBgColor = $r('sys.color.ohos_id_color_sub_background_transparent')
267          }
268        })
269        .onHover((isHover: boolean) => {
270          if (isHover) {
271            this.textArrowBgColor = $r('sys.color.ohos_id_color_hover')
272          } else {
273            this.textArrowBgColor = $r('sys.color.ohos_id_color_sub_background_transparent')
274          }
275        })
276        .onKeyEvent((event) => {
277          if (event.keyCode === KeyCode.KEYCODE_ENTER || event.keyCode === KeyCode.KEYCODE_SPACE) {
278            textArrow.action && textArrow.action()
279          }
280        })
281        .onAreaChange((oldValue: Area, newValue: Area) => {
282          this.arrowWidth = Number(parseInt(newValue.width.toString(), 0))
283        })
284        .stateStyles({
285          focused: {
286            .border({
287              radius: MARGIN_NUM,
288              width: BORDER_WIDTH,
289              color: $r('sys.color.ohos_id_color_focused_outline'),
290              style: BorderStyle.Solid
291            })
292          },
293          normal: {
294            .border({
295              radius: MARGIN_NUM,
296              width: BORDER_WIDTH,
297              color: Color.Transparent
298            })
299          }
300        })
301      }
302    }
303    .onAreaChange((oldValue: Area, newValue: Area) => {
304      this.textArrowWidth = Number(parseInt(newValue.width.toString(), 0))
305    })
306    .constraintSize({ minWidth: this.flexWidth / DIVIDEND_WIDTH })
307    .justifyContent(FlexAlign.End)
308    .margin({ left: SPACE_MARGIN })
309  }
310
311  @Builder ButtonStyle(button: OperationOption) {
312    Row() {
313      Stack() {
314        Row() {
315          if (button != null) {
316            Text(button.value)
317              .maxLines(1)
318              .fontColor($r('sys.color.ohos_id_color_text_primary_activated'))
319              .fontSize($r('sys.float.ohos_id_text_size_button2'))
320              .fontWeight(FontWeight.Medium)
321              .margin({ left: SPACE_MARGIN, right: SPACE_MARGIN })
322              .focusable(true)
323          }
324        }
325        .justifyContent(FlexAlign.End)
326        .alignItems(VerticalAlign.Center)
327        .focusable(true)
328        .height(BUTTON_HEIGHT)
329        .margin({ left: SPACE_MARGIN, right: SPACE_MARGIN })
330        .borderRadius(IMAGE_WIDTH_NUM)
331        .backgroundColor(this.buttonBgColor)
332        .onFocus(() => {
333          this.buttonFocus = true
334        })
335        .onBlur(() => {
336          this.buttonFocus = false
337        })
338        .onTouch((event) => {
339          if (event.type === TouchType.Down) {
340            if (button.action) {
341              button.action()
342            }
343            this.buttonBgColor = $r('sys.color.ohos_id_color_click_effect')
344          }
345          if (event.type === TouchType.Up) {
346            this.buttonBgColor = $r('sys.color.ohos_id_color_sub_background_transparent')
347          }
348        })
349        .onHover((isHover: boolean) => {
350          if (isHover) {
351            this.buttonBgColor = $r('sys.color.ohos_id_color_hover')
352          } else {
353            this.buttonBgColor = $r('sys.color.ohos_id_color_sub_background_transparent')
354          }
355        })
356        .onKeyEvent((event) => {
357          if (event.keyCode === KeyCode.KEYCODE_ENTER || event.keyCode === KeyCode.KEYCODE_SPACE) {
358            button.action && button.action()
359          }
360        })
361        .onAreaChange((oldValue: Area, newValue: Area) => {
362          let flexWidth = Number(parseInt(newValue.width.toString(), 0))
363          this.buttonWidth = flexWidth
364        })
365
366        if (this.buttonFocus) {
367          Row()
368            .height(BUTTON_HEIGHT)
369            .width(this.buttonWidth)
370            .hitTestBehavior(HitTestMode.None)
371            .border({
372              width: BORDER_WIDTH,
373              color: $r('sys.color.ohos_id_color_focused_outline')
374            })
375            .borderRadius(IMAGE_WIDTH_NUM)
376        }
377      }
378    }
379    .constraintSize({ minWidth: this.flexWidth / DIVIDEND_WIDTH })
380    .justifyContent(FlexAlign.End)
381    .focusable(true)
382    .margin({ left: SPACE_MARGIN })
383  }
384
385  build() {
386    Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.End }) {
387      if (this.secondaryTitle != null && this.icon != null) {
388        Row() {
389          this.ListIconStyle({ content: this.secondaryTitle }, this.icon)
390        }.margin({ right: SPACE_MARGIN })
391      } else if (this.secondaryTitle != null && this.primaryTitle != null) {
392        this.SubTextStyle({ content: this.primaryTitle, subContent: this.secondaryTitle })
393      } else if (this.secondaryTitle != null) {
394        this.ListTextStyle({ content: this.secondaryTitle })
395      } else if (this.select != null) {
396        this.SelectStyle(this.select)
397      } else if (this.primaryTitle != null) {
398        this.ContentTextStyle({ content: this.primaryTitle })
399      }
400
401      Row() {
402        if (this.operationType === OperationType.BUTTON && this.operationItem != null) {
403          this.ButtonStyle(this.operationItem[0])
404        }
405        if (this.operationType === OperationType.ICON_GROUP && this.operationItem != null) {
406          Row() {
407            ForEach(this.operationItem, (item, index?: number) => {
408              if (index == 0) {
409                IconGroup({ item: item })
410              }
411              if (index == 1) {
412                IconGroup({ item: item })
413              }
414              if (index == 2) { // Image count
415                IconGroup({ item: item })
416              }
417            })
418          }
419        }
420        if (this.operationType === OperationType.TEXT_ARROW && this.operationItem != null) {
421          this.TextArrowStyle(this.operationItem[0])
422        }
423        if (this.operationType === OperationType.LOADING) {
424          this.LoadingProcessStyle()
425        }
426      }
427    }
428    .focusable(true)
429    .onAreaChange((oldValue: Area, newValue: Area) => {
430      let flexWidth = Number(parseInt(newValue.width.toString(), 0))
431      this.flexWidth = flexWidth - CONSTRAINT_NUM
432    })
433    .padding({ right: $r('sys.float.ohos_id_default_padding_end') })
434    .height(this.isDuplicateLine ? DOUBLE_LINE_HEIGHT : SINGLE_LINE_HEIGHT)
435  }
436}