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