1/* 2 * Copyright (c) 2022-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 { 17 Action, 18 BroadCast, 19 BroadCastConstants, 20 Constants, 21 DateUtil, 22 Log, 23 MediaDataSource, 24 MediaItem, 25 ScreenManager, 26 ThirdSelectManager, 27 UserFileManagerAccess 28} from '@ohos/common'; 29import { IS_HORIZONTAL, THIRD_SELECT_IS_ORIGIN, THUMBNAIL_WIDTH } from '../utils/ThirdSelectConstants'; 30 31const TAG: string = 'thiSel_ThirdSelectedPanel'; 32 33interface WidthAndHeight { 34 height: number; 35 width: number; 36}; 37 38@Component 39export struct ThirdSelectedPanel { 40 onMenuClicked: Function = (): void => {}; 41 maxSelectCount: number = 0; 42 @Provide selectedCount: number = 0; 43 @Link @Watch('onSelectedCountChanged') totalSelectedCount: number; 44 selectManager: ThirdSelectManager | null = null; 45 @State itemArray: Array<MediaItem> = []; 46 @StorageLink(THIRD_SELECT_IS_ORIGIN) isOriginalChecked: boolean = false; 47 @StorageLink(IS_HORIZONTAL) isHorizontal: boolean = ScreenManager.getInstance().isHorizontal(); 48 @Consume broadCast: BroadCast; 49 @Link isShowBar: boolean; 50 @Prop currentUri: string = ''; 51 isBrowserMode: boolean = false; 52 isMultiPick = true; 53 mTransition: string = ''; 54 isFromFa: boolean = false; 55 dataSource: MediaDataSource | null = null; 56 private selectedScroller: Scroller = new Scroller(); 57 58 aboutToAppear(): void { 59 this.selectManager = AppStorage.get<ThirdSelectManager>(Constants.THIRD_SELECT_MANAGER) as ThirdSelectManager; 60 this.onSelectedCountChanged(); 61 } 62 63 onSelectedCountChanged(): void { 64 this.selectedCount = this.totalSelectedCount; 65 this.itemArray = this.selectManager == null ? [] : this.selectManager.getSelectItems(); 66 Log.debug(TAG, `call scroll to edge, current count ${this.itemArray.length} this.selectedCount is: ${this.selectedCount}`); 67 this.selectedScroller.scrollEdge(Edge.End); 68 } 69 70 refreshSelectData(refresh: boolean): void { 71 this.selectedCount = this.totalSelectedCount; 72 this.itemArray = this.selectManager == null ? [] : this.selectManager.getSelectItems(); 73 Log.debug(TAG, `call scroll to edge, current count ${this.itemArray.length}`) 74 this.selectedScroller.scrollEdge(Edge.End); 75 } 76 77 getThumbnailSafe(sourceUri: string, path: string, size?: WidthAndHeight): string { 78 try { 79 if (size) { 80 if (size.width != 0 && size.height != 0) { 81 return `${sourceUri}?oper=thumbnail&width=${size.width}&height=${size.height}&path=${path}`; 82 } else { 83 Log.warn(TAG, 'getThumbnailSafe with width==0 and height==0, so do not use thumbnail' + JSON.stringify(size)); 84 return `${sourceUri}`; 85 } 86 } else { 87 return `${sourceUri}?oper=thumbnail&width=${THUMBNAIL_WIDTH}&height=${THUMBNAIL_WIDTH}&path=${path}`; 88 } 89 } catch (err) { 90 Log.warn(TAG, `get Thumbnail Failed! msg:${err}`); 91 return ''; 92 } 93 } 94 95 @Builder 96 buildRadio() { 97 if (this.isBrowserMode) { 98 Image(this.isOriginalChecked ? $r('app.media.picker_radio_selected') : $r('app.media.picker_radio_unselected')) 99 .key('Original') 100 .width($r('app.float.icon_size')) 101 .aspectRatio(1) 102 .onClick((): void => this.clickOriginButton()) 103 } else { 104 Radio({ value: '', group: this.mTransition }) 105 .key('Original') 106 .checked(this.isOriginalChecked) 107 .margin(0) 108 .onClick((): void => this.clickOriginButton()) 109 } 110 } 111 112 @Builder 113 buildTitle() { 114 Stack() { 115 Row() { 116 Text($r('app.string.selected_photos_count', this.selectedCount, this.maxSelectCount)) 117 .fontSize($r('sys.float.ohos_id_text_size_body1')) 118 .fontFamily($r('app.string.id_text_font_family_regular')) 119 .fontColor(this.selectTextColor()) 120 .fontWeight(FontWeight.Regular) 121 .key('currentSelectCount') 122 123 Button($r('app.string.complete')) 124 .key('Complete') 125 .enabled(this.isButtonEnabled() ? true : false) 126 .opacity(this.isButtonEnabled() ? 1 : $r('app.float.disable_button_opacity')) 127 .fontSize($r('sys.float.ohos_id_text_size_button3')) 128 .fontFamily($r('app.string.id_text_font_family_regular')) 129 .backgroundColor(this.isBrowserMode ? $r('sys.color.ohos_id_color_activated_dark') : $r('sys.color.ohos_id_color_activated')) 130 .width($r('app.float.picker_panel_button_width')) 131 .height($r('app.float.picker_panel_button_height')) 132 .fontWeight(FontWeight.Medium) 133 .onClick(() => { 134 this.onMenuClicked(Action.OK); 135 }) 136 } 137 .width('100%') 138 .height($r('app.float.third_selected_panel_title_height')) 139 .alignItems(VerticalAlign.Center) 140 .justifyContent(FlexAlign.SpaceBetween) 141 .padding({ 142 left: $r('sys.float.ohos_id_max_padding_start'), 143 right: $r('sys.float.ohos_id_max_padding_end') 144 }) 145 146 Row() { 147 this.buildRadio() 148 Text($r('app.string.filter_original_text')) 149 .fontSize($r('sys.float.ohos_id_text_size_body1')) 150 .fontFamily($r('app.string.id_text_font_family_regular')) 151 .fontColor(this.isBrowserMode ? $r('sys.color.ohos_id_color_text_primary_dark') : $r('sys.color.ohos_id_color_text_primary')) 152 .fontWeight(FontWeight.Regular) 153 .margin({ left: $r('app.float.third_selected_toggle_icon_margin_right') }) 154 } 155 .align(Alignment.Center) 156 .alignItems(VerticalAlign.Center) 157 .visibility(this.isFromFa ? Visibility.Hidden : Visibility.Visible) 158 } 159 } 160 161 @Builder 162 buildThumbnailItem(item: MediaItem, index: number) { 163 Stack({ alignContent: Alignment.Start }) { 164 Image(item?.thumbnail) 165 .height('100%') 166 .aspectRatio(1) 167 .objectFit(ImageFit.Cover) 168 .autoResize(false) 169 .onError(() => { 170 Log.error(TAG, 'item Image error'); 171 }) 172 .onComplete(() => { 173 Log.debug(TAG, `Draw the image! ${item?.uri}`); 174 }) 175 .onClick(() => { 176 this.broadCast.emit(BroadCastConstants.JUMP_THIRD_PHOTO_BROWSER, [ 177 '', 178 item, 179 this.getPosition(item), 180 'thiSel_ThirdSelectPhotoGridBase' + item?.getHashCode() + true, 181 true 182 ]); 183 }) 184 // video duration 185 if (item?.mediaType == UserFileManagerAccess.MEDIA_TYPE_VIDEO) { 186 Row() { 187 Text(DateUtil.getFormattedDuration(item?.duration)) 188 .fontSize($r('sys.float.ohos_id_text_size_caption')) 189 .fontFamily($r('app.string.id_text_font_family_regular')) 190 .fontColor($r('app.color.text_color_above_picture')) 191 .lineHeight(12) 192 .margin({ 193 left: $r('app.float.grid_item_text_margin_lr'), 194 bottom: $r('app.float.grid_item_text_margin_bottom') 195 }) 196 } 197 .height('100%') 198 .width('100%') 199 .hitTestBehavior(HitTestMode.None) 200 .alignItems(VerticalAlign.Bottom) 201 } 202 Image($r('app.media.ic_gallery_public_cancel_bg')) 203 .height($r('app.float.icon_size')) 204 .width($r('app.float.icon_size')) 205 .key('ThirdSelectCancel' + item?.uri) 206 .objectFit(ImageFit.Contain) 207 .position({ 208 x: $r('app.float.picker_panel_cancel_x'), 209 y: $r('app.float.picker_panel_cancel_y') 210 }) 211 .onClick(() => { 212 Log.debug(TAG, `click cancel item ${item?.uri}`); 213 this.broadCast.emit(BroadCastConstants.SELECT, [0, item?.uri, false]); 214 }) 215 Image($r('app.media.picker_border_img')) 216 .height('100%') 217 .aspectRatio(1) 218 .fillColor($r('sys.color.ohos_id_color_focused_bg_dark')) 219 .objectFit(ImageFit.Cover) 220 .autoResize(false) 221 .visibility(item?.uri === this.currentUri ? Visibility.Visible : Visibility.None) 222 .hitTestBehavior(HitTestMode.None) 223 } 224 .height('100%') 225 .aspectRatio(1) 226 } 227 228 @Builder 229 buildThumbnailList() { 230 List({ scroller: this.selectedScroller, space: 8 }) { 231 ForEach(this.itemArray, (item: MediaItem, index?: number) => { 232 ListItem() { 233 this.buildThumbnailItem(item, index as number); 234 } 235 .width($r('app.float.third_selected_panel_image_height')) 236 .aspectRatio(1) 237 .margin({ 238 left: index == 0 ? $r('sys.float.ohos_id_max_padding_start') : 0, 239 right: index == this.itemArray.length - 1 ? $r('sys.float.ohos_id_max_padding_end') : 0 240 }) 241 }, (item: MediaItem) => item?.getHashCode()) 242 } 243 .width('100%') 244 .height('100%') 245 .listDirection(Axis.Horizontal) 246 .edgeEffect(EdgeEffect.Spring) 247 .scrollBar(BarState.Off) 248 } 249 250 @Builder 251 buildDefault() { 252 Column() { 253 Text($r('app.string.select_items_to_add')) 254 .fontSize($r('sys.float.ohos_id_text_size_body2')) 255 .fontFamily($r('app.string.id_text_font_family_regular')) 256 .fontColor(this.isBrowserMode ? $r('sys.color.ohos_id_color_secondary_dark') : $r('sys.color.ohos_id_color_secondary')) 257 .fontWeight(FontWeight.Regular) 258 } 259 .width('100%') 260 .height($r('app.float.third_selected_panel_empty_height')) 261 .justifyContent(FlexAlign.Center) 262 .alignItems(HorizontalAlign.Center) 263 .margin({ 264 top: $r('app.float.third_selected_panel_image_padding_top'), 265 }) 266 .padding({ 267 left: $r('sys.float.ohos_id_max_padding_start'), 268 right: $r('sys.float.ohos_id_max_padding_end') 269 }) 270 } 271 272 build() { 273 Column() { 274 this.buildTitle() 275 276 if (this.isMultiPick) { 277 if (this.selectedCount > 0) { 278 Row() { 279 this.buildThumbnailList() 280 } 281 .width('100%') 282 .padding({ 283 top: $r('app.float.third_selected_panel_image_padding_top'), 284 bottom: $r('sys.float.ohos_id_default_padding_bottom_fixed') 285 }) 286 } else { 287 this.buildDefault() 288 } 289 } 290 } 291 .width('100%') 292 .height(this.isMultiPick ? $r('app.float.third_selected_panel_height') : $r('app.float.third_selected_panel_title_height')) 293 .backgroundColor(this.isBrowserMode ? $r('sys.color.ohos_id_color_card_bg_dark') : $r('sys.color.ohos_id_color_card_bg')) 294 .sharedTransition('ThirdSelectPhotoBrowserActionBar', { 295 curve: Curve.Linear, 296 zIndex: Constants.NUMBER_1, 297 type: SharedTransitionEffectType.Static 298 }) 299 .visibility(this.isShowBar ? Visibility.Visible : Visibility.Hidden) 300 } 301 302 private getPosition(item: MediaItem): number { 303 if (this.dataSource) { 304 return this.dataSource.getDataIndex(item) + this.dataSource.getGroupCountBeforeItem(item); 305 } else { 306 return Constants.NOT_FOUND; 307 } 308 } 309 310 private selectTextColor() { 311 let normalColor = this.isBrowserMode ? 312 $r('sys.color.ohos_id_color_text_primary_dark') : $r('sys.color.ohos_id_color_text_primary'); 313 if (!this.isHorizontal) { 314 return normalColor; 315 } 316 let warnColor = this.isBrowserMode ? 317 $r('sys.color.ohos_id_color_warning_dark') : $r('sys.color.ohos_id_color_warning'); 318 return this.isMultiPick && this.selectedCount >= this.maxSelectCount ? warnColor : normalColor; 319 } 320 321 private isButtonEnabled(): boolean { 322 return !this.isMultiPick || this.selectedCount > 0; 323 } 324 325 private clickOriginButton(): void { 326 this.isOriginalChecked = !this.isOriginalChecked; 327 Log.info(TAG, `origin clicked: ${this.isOriginalChecked}`); 328 } 329}