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 */ 15import { WindowConstants } from '@ohos/base/src/main/ets/constants/WindowConstants'; 16import screenManager from '@ohos/base/src/main/ets/manager/ScreenManager'; 17import { DateUtil } from '@ohos/base/src/main/ets/utils/DateUtil'; 18import { TimelineDataItem } from '../data/TimelineDataItem'; 19import { Log } from '@ohos/base/src/main/ets/utils/Log'; 20import { Broadcast } from '@ohos/base/src/main/ets/utils/Broadcast'; 21import { BroadcastConstants } from '@ohos/base/src/main/ets/constants/BroadcastConstants'; 22import { TimelineItemDataSource } from '../vm/TimelineItemDataSource'; 23 24const TAG = "TimelineScrollBar" 25 26@Component 27export struct TimelineScrollBar { 28 scroller: Scroller; 29 dataSource: TimelineItemDataSource; 30 @Link isHideScrollBar: boolean; 31 @State isClickScrollBar: boolean = false; 32 @Consume dateText: string; 33 @Consume broadCast: Broadcast; 34 35 aboutToAppear(): void { 36 } 37 38 nodeGap(count: number): number { 39 let windowHeight: number = screenManager.getWinHeight() - WindowConstants.TOOL_BAR_SIZE; 40 let gridHeight: number = windowHeight - WindowConstants.SCROLL_MARGIN * 2; 41 let gapS = Math.ceil(gridHeight * count / this.dataSource.childCount() - WindowConstants.SCROLL_MARGIN * 2); 42 if (gapS >= WindowConstants.SCROLL_BAR_SIDE_MIN_GAP) { 43 return gapS; 44 } 45 return -1; 46 } 47 48 private isFirst(item: TimelineDataItem): boolean { 49 return this.dataSource.groupItem.indexOf(item) == 0; 50 } 51 52 private isLast(item: TimelineDataItem): boolean { 53 return this.dataSource.groupItem.indexOf(item) == this.dataSource.groupItem.length - 1; 54 } 55 56 private isShowLocalizedYear(item: TimelineDataItem): boolean { 57 if (this.dataSource.groupItem.indexOf(item) > 0) { 58 return DateUtil.getLocalizedYearString(item.dateAdded) != DateUtil.getLocalizedYearString(this.dataSource.getDataByIndex(this.dataSource.groupItem.indexOf(item) - 1).dateAdded); 59 } 60 return true; 61 } 62 63 build() { 64 Stack({ alignContent: Alignment.End }) { 65 if (this.isClickScrollBar && !this.isHideScrollBar) { 66 Column() { 67 ForEach(this.dataSource.groupItem, (year: TimelineDataItem) => { 68 if (this.nodeGap(year.groupChild.length) > 0 || this.isFirst(year) || this.isLast(year)) { 69 Row() { 70 Text(DateUtil.getLocalizedYear(year.dateAdded)) 71 .fontSize($r('sys.float.ohos_id_text_size_body3')) 72 .fontFamily($r('app.string.id_text_font_family_regular')) 73 .fontColor($r('sys.color.ohos_id_color_text_primary')) 74 } 75 .height($r('app.float.scroll_bar_side_text_height_small')) 76 .backgroundColor($r('app.color.scroll_bar_side_text_small_color')) 77 .borderRadius($r('app.float.scroll_bar_side_text_radio')) 78 .padding({ 79 left: $r('app.float.scroll_bar_side_text_padding_horizontal_small'), 80 right: $r('app.float.scroll_bar_side_text_padding_horizontal_small'), 81 top: $r('app.float.scroll_bar_side_text_padding_vertical_small'), 82 bottom: $r('app.float.scroll_bar_side_text_padding_vertical_small') 83 }) 84 .shadow({ 85 radius: $r('app.float.scroll_bar_side_text_shadow_radio'), 86 color: $r('app.color.scroll_bar_side_text_shadow_color'), 87 offsetX: $r('app.float.scroll_bar_side_text_shadow_offsetX'), 88 offsetY: $r('app.float.scroll_bar_side_text_shadow_offsetY'), 89 }) 90 .margin({ 91 bottom: this.nodeGap(year.groupChild.length) 92 }) 93 .visibility(this.isShowLocalizedYear(year) ? Visibility.Visible : Visibility.Hidden) 94 } 95 }, year => JSON.stringify(year)) 96 } 97 .height('100%') 98 .margin({ 99 right: $r('app.float.scroll_bar_margin_small'), 100 top: $r('app.float.max_padding_start'), 101 bottom: $r('app.float.max_padding_end') 102 }) 103 } 104 105 ScrollBar({ 106 scroller: this.scroller, 107 direction: ScrollBarDirection.Vertical, 108 state: this.isHideScrollBar ? BarState.Off : BarState.Auto 109 }) { 110 Row() { 111 if (this.isClickScrollBar) { 112 Row() { 113 Row() { 114 Text(this.dateText) 115 .fontSize($r('sys.float.ohos_id_text_size_sub_title1')) 116 .fontFamily($r('app.string.id_text_font_family_medium')) 117 .fontColor($r('app.color.title_text_color')) 118 } 119 .height($r('app.float.scroll_bar_side_text_height')) 120 .backgroundColor($r('app.color.scroll_bar_side_text_color')) 121 .borderRadius($r('app.float.scroll_bar_side_text_radio')) 122 .padding({ 123 left: $r('app.float.scroll_bar_side_text_padding_horizontal'), 124 right: $r('app.float.scroll_bar_side_text_padding_horizontal'), 125 top: $r('app.float.scroll_bar_side_text_padding_vertical'), 126 bottom: $r('app.float.scroll_bar_side_text_padding_vertical') 127 }) 128 .shadow({ 129 radius: $r('app.float.scroll_bar_side_text_shadow_radio'), 130 color: $r('app.color.scroll_bar_side_text_shadow_color'), 131 offsetX: $r('app.float.scroll_bar_side_text_shadow_offsetX'), 132 offsetY: $r('app.float.scroll_bar_side_text_shadow_offsetY'), 133 }) 134 135 Row() { 136 Image($r("app.media.scroll_press_light")) 137 } 138 .width($r('app.float.scroll_bar_big_width')) 139 .height($r('app.float.scroll_bar_big_height')) 140 .margin({ left: $r('app.float.scroll_bar_side_gap') }) 141 } 142 .width($r('app.float.scroll_press_all_width')) 143 .justifyContent(FlexAlign.End) 144 } else { 145 Row() { 146 Image($r("app.media.scroll_light")) 147 .width($r('app.float.scroll_bar_small_width')) 148 .height($r('app.float.scroll_bar_small_height')) 149 } 150 } 151 } 152 } 153 .height('100%') 154 .width(this.isClickScrollBar 155 ? $r('app.float.scroll_press_all_width') : $r('app.float.scroll_bar_small_width'),) 156 } 157 .onTouch((event: TouchEvent) => { 158 if (this.dateText == '') { 159 Log.warn(TAG, `dateText is null`) 160 this.broadCast.emit(BroadcastConstants.INIT_DATE_TEXT, []) 161 } 162 if (event.type == TouchType.Down) { 163 this.isClickScrollBar = true; 164 } else if (event.type == TouchType.Up) { 165 this.isClickScrollBar = false; 166 } 167 }) 168 } 169}