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