100aff185Sopenharmony_ci/* 200aff185Sopenharmony_ci * Copyright (c) 2022-2023 Huawei Device Co., Ltd. 300aff185Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 400aff185Sopenharmony_ci * you may not use this file except in compliance with the License. 500aff185Sopenharmony_ci * You may obtain a copy of the License at 600aff185Sopenharmony_ci * 700aff185Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 800aff185Sopenharmony_ci * 900aff185Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1000aff185Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1100aff185Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1200aff185Sopenharmony_ci * See the License for the specific language governing permissions and 1300aff185Sopenharmony_ci * limitations under the License. 1400aff185Sopenharmony_ci */ 1500aff185Sopenharmony_ci 1600aff185Sopenharmony_ciimport Curves from '@ohos.curves'; 1700aff185Sopenharmony_ciimport { Log } from '../utils/Log'; 1800aff185Sopenharmony_ciimport { Constants } from '../model/common/Constants'; 1900aff185Sopenharmony_ciimport { Constants as PhotoConstants } from '../model/browser/photo/Constants'; 2000aff185Sopenharmony_ciimport { MediaItem } from '../model/browser/photo/MediaItem'; 2100aff185Sopenharmony_ciimport { DateUtil } from '../utils/DateUtil'; 2200aff185Sopenharmony_ciimport { BroadCast } from '../utils/BroadCast'; 2300aff185Sopenharmony_ciimport { BroadCastConstants } from '../model/common/BroadCastConstants'; 2400aff185Sopenharmony_ciimport { Action } from './browserOperation/Action'; 2500aff185Sopenharmony_ciimport { ImageUtil } from '../utils/ImageUtil'; 2600aff185Sopenharmony_ciimport { ColumnSize, ScreenManager } from '../model/common/ScreenManager'; 2700aff185Sopenharmony_ciimport { TraceControllerUtils } from '../utils/TraceControllerUtils'; 2800aff185Sopenharmony_ciimport { UserFileManagerAccess } from '../access/UserFileManagerAccess'; 2900aff185Sopenharmony_ciimport { MultimodalInputManager } from '../model/common/MultimodalInputManager'; 3000aff185Sopenharmony_ciimport { BigDataConstants, ReportToBigDataUtil } from '../utils/ReportToBigDataUtil'; 3100aff185Sopenharmony_ciimport { AlbumDefine } from '../model/browser/AlbumDefine'; 3200aff185Sopenharmony_ciimport { MediaDataSource } from '../model/browser/photo/MediaDataSource'; 3300aff185Sopenharmony_ciimport { BroadCastManager } from '../model/common/BroadCastManager'; 3400aff185Sopenharmony_ci 3500aff185Sopenharmony_ciconst TAG: string = 'common_ImageGridItemComponent'; 3600aff185Sopenharmony_ci 3700aff185Sopenharmony_ci@Extend(Image) 3800aff185Sopenharmony_cifunction focusSetting(uri: string, handleEvent: Function) { 3900aff185Sopenharmony_ci .key('ImageGridFocus_' + uri) 4000aff185Sopenharmony_ci .focusable(true) 4100aff185Sopenharmony_ci .onKeyEvent((event?: KeyEvent) => { 4200aff185Sopenharmony_ci handleEvent((event as KeyEvent)); 4300aff185Sopenharmony_ci }) 4400aff185Sopenharmony_ci} 4500aff185Sopenharmony_ci 4600aff185Sopenharmony_ciinterface Msg { 4700aff185Sopenharmony_ci from: string; 4800aff185Sopenharmony_ci} 4900aff185Sopenharmony_ci 5000aff185Sopenharmony_ci// General grid picture control 5100aff185Sopenharmony_ci@Component 5200aff185Sopenharmony_ciexport struct ImageGridItemComponent { 5300aff185Sopenharmony_ci item: MediaItem | null = null; 5400aff185Sopenharmony_ci @StorageLink('isHorizontal') isHorizontal: boolean = ScreenManager.getInstance().isHorizontal(); 5500aff185Sopenharmony_ci @Consume @Watch('onModeChange') isSelectedMode: boolean; 5600aff185Sopenharmony_ci @State isSelected: boolean = false; 5700aff185Sopenharmony_ci isRecycle: boolean = false; 5800aff185Sopenharmony_ci @Consume broadCast: BroadCast; 5900aff185Sopenharmony_ci @Consume @Watch('onShow') isShow: boolean; 6000aff185Sopenharmony_ci @Link selectedCount: number; 6100aff185Sopenharmony_ci @State autoResize: boolean = true; 6200aff185Sopenharmony_ci loaded = false; 6300aff185Sopenharmony_ci mPosition: number = 0; 6400aff185Sopenharmony_ci pageName = ''; 6500aff185Sopenharmony_ci @State isLoadImageError: boolean = false; 6600aff185Sopenharmony_ci @State pressAnimScale: number = 1.0; 6700aff185Sopenharmony_ci @State recycleDays: number = 0; 6800aff185Sopenharmony_ci @Consume rightClickMenuList: Array<Action>; 6900aff185Sopenharmony_ci onMenuClicked: Function = (): void => {}; 7000aff185Sopenharmony_ci onMenuClickedForSingleItem: Function = (): void => {}; 7100aff185Sopenharmony_ci @State geometryTransitionString: string = 'default_id'; 7200aff185Sopenharmony_ci @State isTap: boolean = false; 7300aff185Sopenharmony_ci @StorageLink('placeholderIndex') @Watch('verifyTapStatus') placeholderIndex: number = -1; 7400aff185Sopenharmony_ci @StorageLink('geometryTransitionBrowserId') @Watch('verifyTapStatus') geometryTransitionBrowserId: string = ''; 7500aff185Sopenharmony_ci private imageThumbnail: string = ''; 7600aff185Sopenharmony_ci private transitionId: string = ''; 7700aff185Sopenharmony_ci private isEnteringPhoto = false; 7800aff185Sopenharmony_ci private isThird = false; 7900aff185Sopenharmony_ci private isThirdMultiPick: boolean = false; 8000aff185Sopenharmony_ci private albumUri: string = ''; 8100aff185Sopenharmony_ci private dataSource: MediaDataSource | null = null; 8200aff185Sopenharmony_ci private geometryTapIndex: number = 0; 8300aff185Sopenharmony_ci private isTapStatusChange: boolean = false; 8400aff185Sopenharmony_ci private appBroadCast: BroadCast = BroadCastManager.getInstance().getBroadCast(); 8500aff185Sopenharmony_ci private updateSelectFunc: Function = (updateUri: string, select: boolean): void => 8600aff185Sopenharmony_ci this.updateSelect(updateUri, select); 8700aff185Sopenharmony_ci 8800aff185Sopenharmony_ci verifyTapStatus() { 8900aff185Sopenharmony_ci if (this.placeholderIndex === Constants.INVALID) { 9000aff185Sopenharmony_ci this.isTap = false; 9100aff185Sopenharmony_ci return; 9200aff185Sopenharmony_ci } 9300aff185Sopenharmony_ci this.updateGeometryTapInfo(); 9400aff185Sopenharmony_ci let pageFromGlobal = this.geometryTransitionBrowserId.split(':')[0]; 9500aff185Sopenharmony_ci let pageFrom = this.geometryTransitionString.split(':')[0]; 9600aff185Sopenharmony_ci let oldTapStatus = this.isTap; 9700aff185Sopenharmony_ci let newTapStatus = (pageFromGlobal === pageFrom) && (this.placeholderIndex === this.geometryTapIndex); 9800aff185Sopenharmony_ci this.isTapStatusChange = oldTapStatus !== newTapStatus; 9900aff185Sopenharmony_ci this.isTap = newTapStatus; 10000aff185Sopenharmony_ci if (this.isTap) { 10100aff185Sopenharmony_ci this.geometryTransitionString = this.geometryTransitionBrowserId; 10200aff185Sopenharmony_ci Log.debug(TAG, 'update placeholderIndex = ' + this.placeholderIndex + 10300aff185Sopenharmony_ci 'geometryTapIndex = ' + this.geometryTapIndex + ', isTap = ' + this.isTap + 10400aff185Sopenharmony_ci ', geometryTransitionString = ' + this.geometryTransitionString); 10500aff185Sopenharmony_ci } 10600aff185Sopenharmony_ci } 10700aff185Sopenharmony_ci 10800aff185Sopenharmony_ci aboutToAppear(): void { 10900aff185Sopenharmony_ci this.imageThumbnail = this.item?.thumbnail ?? ''; 11000aff185Sopenharmony_ci this.albumUri = AppStorage.get<string>(Constants.KEY_OF_ALBUM_URI) as string; 11100aff185Sopenharmony_ci if (this.item != null) { 11200aff185Sopenharmony_ci if (this.isSelected) { 11300aff185Sopenharmony_ci this.transitionId = `${this.item.hashCode}_${this.albumUri}_${this.isSelected}`; 11400aff185Sopenharmony_ci } else { 11500aff185Sopenharmony_ci this.transitionId = `${this.item.hashCode}_${this.albumUri}`; 11600aff185Sopenharmony_ci } 11700aff185Sopenharmony_ci } 11800aff185Sopenharmony_ci if (this.isRecycle) { 11900aff185Sopenharmony_ci this.calculateRecycleDays(); 12000aff185Sopenharmony_ci } 12100aff185Sopenharmony_ci Log.info(TAG, `transitionId: ${this.transitionId}`); 12200aff185Sopenharmony_ci this.isTap = this.geometryTransitionString === this.geometryTransitionBrowserId; 12300aff185Sopenharmony_ci this.appBroadCast.on(BroadCastConstants.UPDATE_SELECT, this.updateSelectFunc); 12400aff185Sopenharmony_ci } 12500aff185Sopenharmony_ci 12600aff185Sopenharmony_ci updateSelect(updateUri: string, select: boolean): void { 12700aff185Sopenharmony_ci if (updateUri === this.item?.uri) { 12800aff185Sopenharmony_ci this.isSelected = select; 12900aff185Sopenharmony_ci } 13000aff185Sopenharmony_ci } 13100aff185Sopenharmony_ci 13200aff185Sopenharmony_ci aboutToDisappear(): void { 13300aff185Sopenharmony_ci this.appBroadCast.off(BroadCastConstants.UPDATE_SELECT, this.updateSelectFunc); 13400aff185Sopenharmony_ci this.resetPressAnim(); 13500aff185Sopenharmony_ci } 13600aff185Sopenharmony_ci 13700aff185Sopenharmony_ci onModeChange(newMode: boolean): void { 13800aff185Sopenharmony_ci Log.debug(TAG, `newMode ${newMode}`); 13900aff185Sopenharmony_ci if (!this.isSelectedMode) { 14000aff185Sopenharmony_ci this.isSelected = false; 14100aff185Sopenharmony_ci } 14200aff185Sopenharmony_ci } 14300aff185Sopenharmony_ci 14400aff185Sopenharmony_ci onAllSelect(newMode: boolean): boolean { 14500aff185Sopenharmony_ci Log.debug(TAG, `onAllSelect ${newMode}`); 14600aff185Sopenharmony_ci return newMode; 14700aff185Sopenharmony_ci } 14800aff185Sopenharmony_ci 14900aff185Sopenharmony_ci async routePage(isError: boolean) { 15000aff185Sopenharmony_ci Log.info(TAG, `routePage ${isError}`); 15100aff185Sopenharmony_ci try { 15200aff185Sopenharmony_ci TraceControllerUtils.startTrace('enterPhotoBrowser'); 15300aff185Sopenharmony_ci if (this.isThird) { 15400aff185Sopenharmony_ci this.broadCast.emit(BroadCastConstants.JUMP_THIRD_PHOTO_BROWSER, [this.pageName, this.item]); 15500aff185Sopenharmony_ci } else { 15600aff185Sopenharmony_ci this.broadCast.emit(BroadCastConstants.JUMP_PHOTO_BROWSER, [this.pageName, this.item]); 15700aff185Sopenharmony_ci } 15800aff185Sopenharmony_ci } catch (err) { 15900aff185Sopenharmony_ci Log.error(TAG, `fail callback, code: ${err.code}, msg: ${err.msg}`); 16000aff185Sopenharmony_ci } 16100aff185Sopenharmony_ci } 16200aff185Sopenharmony_ci 16300aff185Sopenharmony_ci async routeToPreviewPage() { 16400aff185Sopenharmony_ci try { 16500aff185Sopenharmony_ci Log.info(TAG, 'routeToPreviewPage'); 16600aff185Sopenharmony_ci this.updateGeometryTapInfo(); 16700aff185Sopenharmony_ci this.broadCast.emit(BroadCastConstants.JUMP_THIRD_PHOTO_BROWSER, 16800aff185Sopenharmony_ci [this.pageName, this.item, this.geometryTapIndex, this.geometryTransitionString]); 16900aff185Sopenharmony_ci } catch (err) { 17000aff185Sopenharmony_ci Log.error(TAG, `fail callback, code: ${err.code}, msg: ${err.msg}`); 17100aff185Sopenharmony_ci } 17200aff185Sopenharmony_ci } 17300aff185Sopenharmony_ci 17400aff185Sopenharmony_ci selectStateChange() { 17500aff185Sopenharmony_ci Log.info(TAG, 'change selected.'); 17600aff185Sopenharmony_ci let newState = !this.isSelected; 17700aff185Sopenharmony_ci AppStorage.setOrCreate('focusUpdate', true); 17800aff185Sopenharmony_ci if (this.item != null && this.item.uri) { 17900aff185Sopenharmony_ci this.mPosition = this.getPosition(); 18000aff185Sopenharmony_ci this.broadCast.emit(BroadCastConstants.SELECT, 18100aff185Sopenharmony_ci [this.mPosition, this.item.uri, newState, (isSelected: boolean): void => { 18200aff185Sopenharmony_ci let itemUri: string = this.item == null ? '' : this.item.uri; 18300aff185Sopenharmony_ci Log.info(TAG, `enter callback, select status ${this.mPosition} ${itemUri} ${newState} ${this.isSelected}`); 18400aff185Sopenharmony_ci this.isSelected = isSelected == undefined ? newState : isSelected; 18500aff185Sopenharmony_ci }]); 18600aff185Sopenharmony_ci } 18700aff185Sopenharmony_ci } 18800aff185Sopenharmony_ci 18900aff185Sopenharmony_ci @Builder 19000aff185Sopenharmony_ci RightClickMenuBuilder() { 19100aff185Sopenharmony_ci Column() { 19200aff185Sopenharmony_ci ForEach(this.rightClickMenuList, (menu: Action) => { 19300aff185Sopenharmony_ci Text(this.changeTextResToPlural(menu)) 19400aff185Sopenharmony_ci .key('RightClick_' + this.mPosition + menu.componentKey) 19500aff185Sopenharmony_ci .width('100%') 19600aff185Sopenharmony_ci .height($r('app.float.menu_height')) 19700aff185Sopenharmony_ci .fontColor(menu.fillColor) 19800aff185Sopenharmony_ci .fontSize($r('sys.float.ohos_id_text_size_body1')) 19900aff185Sopenharmony_ci .fontWeight(FontWeight.Regular) 20000aff185Sopenharmony_ci .maxLines(2) 20100aff185Sopenharmony_ci .textOverflow({ overflow: TextOverflow.Ellipsis }) 20200aff185Sopenharmony_ci .onClick(() => { 20300aff185Sopenharmony_ci Log.info(TAG, 'on right click menu, action: ' + menu.actionID); 20400aff185Sopenharmony_ci if (menu == Action.MULTISELECT) { 20500aff185Sopenharmony_ci this.selectStateChange(); 20600aff185Sopenharmony_ci } else { 20700aff185Sopenharmony_ci // 1.当鼠标对着被选中的项按右键时,菜单中的功能,针对所有被选中的项做处理 20800aff185Sopenharmony_ci // 2.当鼠标对着未被选中的项按右键时,菜单中的功能,仅针对当前项处理,其他被选中的项不做任何处理 20900aff185Sopenharmony_ci if (this.isSelectedMode && this.isSelected) { 21000aff185Sopenharmony_ci this.onMenuClicked && this.onMenuClicked(menu); 21100aff185Sopenharmony_ci } else { 21200aff185Sopenharmony_ci this.onMenuClickedForSingleItem && this.onMenuClickedForSingleItem(menu, this.item); 21300aff185Sopenharmony_ci } 21400aff185Sopenharmony_ci } 21500aff185Sopenharmony_ci }) 21600aff185Sopenharmony_ci }, (item: Action) => JSON.stringify(item)) 21700aff185Sopenharmony_ci } 21800aff185Sopenharmony_ci .width(ScreenManager.getInstance().getColumnsWidth(ColumnSize.COLUMN_TWO)) 21900aff185Sopenharmony_ci .borderRadius($r('sys.float.ohos_id_corner_radius_card')) 22000aff185Sopenharmony_ci .padding({ 22100aff185Sopenharmony_ci top: $r('app.float.menu_padding_vertical'), 22200aff185Sopenharmony_ci bottom: $r('app.float.menu_padding_vertical'), 22300aff185Sopenharmony_ci left: $r('app.float.menu_padding_horizontal'), 22400aff185Sopenharmony_ci right: $r('app.float.menu_padding_horizontal') 22500aff185Sopenharmony_ci }) 22600aff185Sopenharmony_ci .backgroundColor(Color.White) 22700aff185Sopenharmony_ci .margin({ 22800aff185Sopenharmony_ci right: $r('sys.float.ohos_id_max_padding_end'), 22900aff185Sopenharmony_ci bottom: $r('app.float.menu_margin_bottom') 23000aff185Sopenharmony_ci }) 23100aff185Sopenharmony_ci } 23200aff185Sopenharmony_ci 23300aff185Sopenharmony_ci 23400aff185Sopenharmony_ci build() { 23500aff185Sopenharmony_ci Column() { 23600aff185Sopenharmony_ci if (this.isTap) { 23700aff185Sopenharmony_ci Column() { 23800aff185Sopenharmony_ci } 23900aff185Sopenharmony_ci .aspectRatio(1) 24000aff185Sopenharmony_ci .rotate({ x: 0, y: 0, z: 1, angle: 0 }) 24100aff185Sopenharmony_ci .backgroundColor($r('app.color.default_background_color')) 24200aff185Sopenharmony_ci .width('100%') 24300aff185Sopenharmony_ci .height('100%') 24400aff185Sopenharmony_ci .zIndex(-1) 24500aff185Sopenharmony_ci } else { 24600aff185Sopenharmony_ci this.buildNormal() 24700aff185Sopenharmony_ci } 24800aff185Sopenharmony_ci } 24900aff185Sopenharmony_ci } 25000aff185Sopenharmony_ci 25100aff185Sopenharmony_ci @Builder 25200aff185Sopenharmony_ci buildImage() { 25300aff185Sopenharmony_ci Image(this.imageThumbnail) 25400aff185Sopenharmony_ci .syncLoad(this.isSelectedMode) 25500aff185Sopenharmony_ci .width('100%') 25600aff185Sopenharmony_ci .height('100%') 25700aff185Sopenharmony_ci .rotate({ x: 0, y: 0, z: 1, angle: 0 }) 25800aff185Sopenharmony_ci .objectFit(ImageFit.Cover) 25900aff185Sopenharmony_ci .autoResize(false) 26000aff185Sopenharmony_ci .focusSetting(this.item == null ? '' : this.item.uri, (event: KeyEvent): void => this.handleKeyEvent(event)) 26100aff185Sopenharmony_ci .onError(() => { 26200aff185Sopenharmony_ci this.isLoadImageError = true; 26300aff185Sopenharmony_ci AppStorage.setOrCreate('focusUpdate', true); 26400aff185Sopenharmony_ci Log.error(TAG, 'item Image error'); 26500aff185Sopenharmony_ci }) 26600aff185Sopenharmony_ci .onComplete(() => { 26700aff185Sopenharmony_ci Log.debug(TAG, `Draw the image! ${this.imageThumbnail}`); 26800aff185Sopenharmony_ci }) 26900aff185Sopenharmony_ci .onAppear(() => { 27000aff185Sopenharmony_ci this.requestFocus('ImageGridFocus_'); 27100aff185Sopenharmony_ci }) 27200aff185Sopenharmony_ci .geometryTransition(this.geometryTransitionString) 27300aff185Sopenharmony_ci .transition(TransitionEffect.asymmetric( 27400aff185Sopenharmony_ci TransitionEffect.scale({ x: AppStorage.get('geometryScale'), y: AppStorage.get('geometryScale') }), 27500aff185Sopenharmony_ci TransitionEffect.opacity(0.99))) 27600aff185Sopenharmony_ci 27700aff185Sopenharmony_ci if (this.geometryTransitionBrowserId === '' || !this.isTapStatusChange) { 27800aff185Sopenharmony_ci this.buildIcon(); 27900aff185Sopenharmony_ci } 28000aff185Sopenharmony_ci } 28100aff185Sopenharmony_ci 28200aff185Sopenharmony_ci @Builder 28300aff185Sopenharmony_ci buildIcon() { 28400aff185Sopenharmony_ci if (this.item != null && this.item.mediaType == UserFileManagerAccess.MEDIA_TYPE_VIDEO || this.isRecycle) { 28500aff185Sopenharmony_ci Row() { 28600aff185Sopenharmony_ci // 缩略图左下角视频时长 28700aff185Sopenharmony_ci if (this.item != null && this.item.mediaType == UserFileManagerAccess.MEDIA_TYPE_VIDEO) { 28800aff185Sopenharmony_ci Text(DateUtil.getFormattedDuration(this.item.duration)) 28900aff185Sopenharmony_ci .fontSize($r('sys.float.ohos_id_text_size_caption')) 29000aff185Sopenharmony_ci .fontFamily($r('app.string.id_text_font_family_regular')) 29100aff185Sopenharmony_ci .fontColor($r('app.color.text_color_above_picture')) 29200aff185Sopenharmony_ci .lineHeight(12) 29300aff185Sopenharmony_ci .margin({ 29400aff185Sopenharmony_ci left: $r('app.float.grid_item_text_margin_lr'), 29500aff185Sopenharmony_ci bottom: $r('app.float.grid_item_text_margin_bottom') 29600aff185Sopenharmony_ci }) 29700aff185Sopenharmony_ci .key('VideoDurationOfIndex' + this.mPosition) 29800aff185Sopenharmony_ci } 29900aff185Sopenharmony_ci // 缩略图右下角距离删除天数 30000aff185Sopenharmony_ci if (this.isRecycle && !this.isSelectedMode) { 30100aff185Sopenharmony_ci Blank() 30200aff185Sopenharmony_ci 30300aff185Sopenharmony_ci Text($r('app.plural.recycle_days', this.recycleDays, this.recycleDays)) 30400aff185Sopenharmony_ci .fontSize($r('sys.float.ohos_id_text_size_caption')) 30500aff185Sopenharmony_ci .fontFamily($r('app.string.id_text_font_family_regular')) 30600aff185Sopenharmony_ci .fontColor(this.recycleDays <= Constants.RECYCLE_DAYS_WARN ? $r('sys.color.ohos_id_color_warning') : $r('app.color.text_color_above_picture')) 30700aff185Sopenharmony_ci .lineHeight(12) 30800aff185Sopenharmony_ci .margin({ 30900aff185Sopenharmony_ci right: $r('app.float.grid_item_text_margin_lr'), 31000aff185Sopenharmony_ci bottom: $r('app.float.grid_item_text_margin_bottom') 31100aff185Sopenharmony_ci }) 31200aff185Sopenharmony_ci } 31300aff185Sopenharmony_ci } 31400aff185Sopenharmony_ci .position({ x: '0%', y: '50%' }) 31500aff185Sopenharmony_ci .height('50%') 31600aff185Sopenharmony_ci .width('100%') 31700aff185Sopenharmony_ci .alignItems(VerticalAlign.Bottom) 31800aff185Sopenharmony_ci .linearGradient({ angle: 0, colors: 31900aff185Sopenharmony_ci [[$r('app.color.album_cover_gradient_start_color'), 0], [$r('app.color.transparent'), 1.0]] }) 32000aff185Sopenharmony_ci } 32100aff185Sopenharmony_ci 32200aff185Sopenharmony_ci if (this.item != null && this.item.isFavor) { 32300aff185Sopenharmony_ci Image($r('app.media.ic_favorite_overlay')) 32400aff185Sopenharmony_ci .height($r('app.float.overlay_icon_size')) 32500aff185Sopenharmony_ci .width($r('app.float.overlay_icon_size')) 32600aff185Sopenharmony_ci .fillColor($r('sys.color.ohos_id_color_primary_dark')) 32700aff185Sopenharmony_ci .objectFit(ImageFit.Contain) 32800aff185Sopenharmony_ci .position({ x: '100%', y: '0%' }) 32900aff185Sopenharmony_ci .markAnchor({ 33000aff185Sopenharmony_ci x: $r('app.float.grid_item_favor_markAnchor_x'), 33100aff185Sopenharmony_ci y: $r('app.float.grid_item_favor_markAnchor_y') 33200aff185Sopenharmony_ci }) 33300aff185Sopenharmony_ci .key('Favor_' + this.mPosition) 33400aff185Sopenharmony_ci } 33500aff185Sopenharmony_ci 33600aff185Sopenharmony_ci // 当三方拉起 picker 时, 只有多选模式下才显示蒙层 33700aff185Sopenharmony_ci if (this.isSelected && this.isSelectedMode && (!this.isThird || this.isThirdMultiPick)) { 33800aff185Sopenharmony_ci Column() 33900aff185Sopenharmony_ci .key('MaskLayer_' + this.mPosition) 34000aff185Sopenharmony_ci .height('100%') 34100aff185Sopenharmony_ci .width('100%') 34200aff185Sopenharmony_ci .backgroundColor($r('app.color.item_selection_bg_color')) 34300aff185Sopenharmony_ci } 34400aff185Sopenharmony_ci 34500aff185Sopenharmony_ci // 缩略图上方功能图标 34600aff185Sopenharmony_ci if (this.isSelectedMode) { 34700aff185Sopenharmony_ci Image($r('app.media.ic_photo_preview')) 34800aff185Sopenharmony_ci .key('Previewer_' + this.mPosition) 34900aff185Sopenharmony_ci .height($r('app.float.icon_size')) 35000aff185Sopenharmony_ci .width($r('app.float.icon_size')) 35100aff185Sopenharmony_ci .position({ x: '0%', y: '0%' }) 35200aff185Sopenharmony_ci .markAnchor({ 35300aff185Sopenharmony_ci x: $r('app.float.grid_item_preview_padding'), 35400aff185Sopenharmony_ci y: $r('app.float.grid_item_preview_padding') 35500aff185Sopenharmony_ci }) 35600aff185Sopenharmony_ci .onClick(() => { 35700aff185Sopenharmony_ci Log.info(TAG, 'onClick loadThumbnailUri' + this.imageThumbnail); 35800aff185Sopenharmony_ci this.routeToPreviewPage(); 35900aff185Sopenharmony_ci Log.info(TAG, 'expand.'); 36000aff185Sopenharmony_ci }) 36100aff185Sopenharmony_ci } 36200aff185Sopenharmony_ci if (this.isSelectedMode && (!this.isThird || this.isThirdMultiPick)) { 36300aff185Sopenharmony_ci Checkbox() 36400aff185Sopenharmony_ci .key('Selector_' + this.mPosition) 36500aff185Sopenharmony_ci .select(this.isSelected) 36600aff185Sopenharmony_ci .margin(0) 36700aff185Sopenharmony_ci .position({ x: '100%', y: '100%' }) 36800aff185Sopenharmony_ci .markAnchor({ 36900aff185Sopenharmony_ci x: $r('app.float.grid_item_checkbox_markAnchor'), 37000aff185Sopenharmony_ci y: $r('app.float.grid_item_checkbox_markAnchor') 37100aff185Sopenharmony_ci }) 37200aff185Sopenharmony_ci .focusable(false) 37300aff185Sopenharmony_ci .hitTestBehavior(HitTestMode.None) 37400aff185Sopenharmony_ci } 37500aff185Sopenharmony_ci } 37600aff185Sopenharmony_ci 37700aff185Sopenharmony_ci @Builder 37800aff185Sopenharmony_ci buildNormal() { 37900aff185Sopenharmony_ci Stack({ alignContent: Alignment.Start }) { 38000aff185Sopenharmony_ci // 缩略图 38100aff185Sopenharmony_ci if (this.isLoadImageError) { 38200aff185Sopenharmony_ci Image((this.item != null && this.item.mediaType == UserFileManagerAccess.MEDIA_TYPE_VIDEO) 38300aff185Sopenharmony_ci ? $r('app.media.alt_video_placeholder') : $r('app.media.alt_placeholder')) 38400aff185Sopenharmony_ci .aspectRatio(1) 38500aff185Sopenharmony_ci .rotate({ x: 0, y: 0, z: 1, angle: 0 }) 38600aff185Sopenharmony_ci .objectFit(ImageFit.Cover) 38700aff185Sopenharmony_ci .autoResize(false) 38800aff185Sopenharmony_ci .focusSetting(this.item == null ? '' : this.item.uri, (event: KeyEvent): void => this.handleKeyEvent(event)) 38900aff185Sopenharmony_ci .onAppear(() => { 39000aff185Sopenharmony_ci Log.debug(TAG, `appear the default image!`); 39100aff185Sopenharmony_ci }) 39200aff185Sopenharmony_ci 39300aff185Sopenharmony_ci if (this.geometryTransitionBrowserId === '' || !this.isTapStatusChange) { 39400aff185Sopenharmony_ci this.buildIcon(); 39500aff185Sopenharmony_ci } 39600aff185Sopenharmony_ci } else { 39700aff185Sopenharmony_ci if (this.albumUri === UserFileManagerAccess.getInstance() 39800aff185Sopenharmony_ci .getSystemAlbumUri(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE) || 39900aff185Sopenharmony_ci this.pageName === Constants.PHOTO_TRANSITION_TIMELINE) { 40000aff185Sopenharmony_ci this.buildImage(); 40100aff185Sopenharmony_ci } else { 40200aff185Sopenharmony_ci Stack() { 40300aff185Sopenharmony_ci this.buildImage(); 40400aff185Sopenharmony_ci } 40500aff185Sopenharmony_ci .borderRadius(0) 40600aff185Sopenharmony_ci .clip(true) 40700aff185Sopenharmony_ci .geometryTransition(this.transitionId) 40800aff185Sopenharmony_ci } 40900aff185Sopenharmony_ci } 41000aff185Sopenharmony_ci } 41100aff185Sopenharmony_ci .key('Gesture_' + this.mPosition) 41200aff185Sopenharmony_ci .height('100%') 41300aff185Sopenharmony_ci .width('100%') 41400aff185Sopenharmony_ci .scale({ 41500aff185Sopenharmony_ci x: this.pressAnimScale, 41600aff185Sopenharmony_ci y: this.pressAnimScale 41700aff185Sopenharmony_ci }) 41800aff185Sopenharmony_ci .onTouch(event => { 41900aff185Sopenharmony_ci Log.debug(TAG, `onTouch trigger: isSelectedMode: ${this.isSelectedMode}, 42000aff185Sopenharmony_ci isEnteringPhoto: ${this.isEnteringPhoto}, ${JSON.stringify(event)}`); 42100aff185Sopenharmony_ci if (this.isSelectedMode) { 42200aff185Sopenharmony_ci return; 42300aff185Sopenharmony_ci } 42400aff185Sopenharmony_ci 42500aff185Sopenharmony_ci // Press animation 42600aff185Sopenharmony_ci if (event?.type === TouchType.Down) { 42700aff185Sopenharmony_ci animateTo({ 42800aff185Sopenharmony_ci duration: Constants.PRESS_ANIM_DURATION, 42900aff185Sopenharmony_ci curve: Curve.Ease 43000aff185Sopenharmony_ci }, () => { 43100aff185Sopenharmony_ci this.pressAnimScale = Constants.PRESS_ANIM_SCALE; 43200aff185Sopenharmony_ci }) 43300aff185Sopenharmony_ci } 43400aff185Sopenharmony_ci 43500aff185Sopenharmony_ci if ((event?.type == TouchType.Up || event?.type == TouchType.Cancel) && this.pressAnimScale != 1) { 43600aff185Sopenharmony_ci animateTo({ 43700aff185Sopenharmony_ci duration: Constants.PRESS_ANIM_DURATION, 43800aff185Sopenharmony_ci curve: Curve.Ease 43900aff185Sopenharmony_ci }, () => { 44000aff185Sopenharmony_ci this.pressAnimScale = 1; 44100aff185Sopenharmony_ci }) 44200aff185Sopenharmony_ci } 44300aff185Sopenharmony_ci }) 44400aff185Sopenharmony_ci .gesture(GestureGroup(GestureMode.Exclusive, 44500aff185Sopenharmony_ci TapGesture().onAction((event?: GestureEvent) => { 44600aff185Sopenharmony_ci let ret: boolean = focusControl.requestFocus('ImageGridFocus_' + (this.item == null ? '' : this.item.uri)); 44700aff185Sopenharmony_ci if (ret !== true) { 44800aff185Sopenharmony_ci let itemUri: string = this.item == null ? '' : this.item.uri; 44900aff185Sopenharmony_ci Log.error(TAG, `requestFocus${'ImageGridFocus_' + itemUri}, ret:${ret}`); 45000aff185Sopenharmony_ci } 45100aff185Sopenharmony_ci let msg: Msg = { 45200aff185Sopenharmony_ci from: BigDataConstants.BY_CLICK, 45300aff185Sopenharmony_ci } 45400aff185Sopenharmony_ci ReportToBigDataUtil.report(BigDataConstants.ENTER_PHOTO_BROWSER_WAY, msg); 45500aff185Sopenharmony_ci this.openPhotoBrowser(); 45600aff185Sopenharmony_ci }), 45700aff185Sopenharmony_ci LongPressGesture().onAction((event?: GestureEvent) => { 45800aff185Sopenharmony_ci Log.info(TAG, `LongPressGesture ${event as GestureEvent}`); 45900aff185Sopenharmony_ci this.selectStateChange(); 46000aff185Sopenharmony_ci this.pressAnimScale = 1; 46100aff185Sopenharmony_ci }) 46200aff185Sopenharmony_ci )) 46300aff185Sopenharmony_ci } 46400aff185Sopenharmony_ci 46500aff185Sopenharmony_ci private resetPressAnim(): void { 46600aff185Sopenharmony_ci this.pressAnimScale = 1; 46700aff185Sopenharmony_ci this.isEnteringPhoto = false; 46800aff185Sopenharmony_ci } 46900aff185Sopenharmony_ci 47000aff185Sopenharmony_ci private onShow(): void { 47100aff185Sopenharmony_ci this.resetPressAnim(); 47200aff185Sopenharmony_ci } 47300aff185Sopenharmony_ci 47400aff185Sopenharmony_ci private generateSampleSize(imageWidth: number, imageHeight: number): number { 47500aff185Sopenharmony_ci let width = ScreenManager.getInstance().getWinWidth(); 47600aff185Sopenharmony_ci let height = ScreenManager.getInstance().getWinHeight(); 47700aff185Sopenharmony_ci width = width == 0 ? ScreenManager.DEFAULT_WIDTH : width; 47800aff185Sopenharmony_ci height = height == 0 ? ScreenManager.DEFAULT_HEIGHT : height; 47900aff185Sopenharmony_ci let maxNumOfPixels = width * height; 48000aff185Sopenharmony_ci let minSide = Math.min(width, height); 48100aff185Sopenharmony_ci return ImageUtil.computeSampleSize(imageWidth, imageHeight, minSide, maxNumOfPixels); 48200aff185Sopenharmony_ci } 48300aff185Sopenharmony_ci 48400aff185Sopenharmony_ci private changeTextResToPlural(action: Action): Resource { 48500aff185Sopenharmony_ci let textStr: Resource = action.textRes; 48600aff185Sopenharmony_ci if (Action.RECOVER.equals(action)) { 48700aff185Sopenharmony_ci textStr = this.isSelected 48800aff185Sopenharmony_ci ? $r('app.plural.action_recover_count', this.selectedCount, this.selectedCount) 48900aff185Sopenharmony_ci : $r('app.string.action_recover'); 49000aff185Sopenharmony_ci } else if (Action.DELETE.equals(action)) { 49100aff185Sopenharmony_ci textStr = this.isSelected 49200aff185Sopenharmony_ci ? $r('app.plural.action_delete_count', this.selectedCount, this.selectedCount) 49300aff185Sopenharmony_ci : $r('app.string.action_delete'); 49400aff185Sopenharmony_ci } else if (Action.MOVE.equals(action)) { 49500aff185Sopenharmony_ci textStr = this.isSelected 49600aff185Sopenharmony_ci ? $r('app.plural.move_to_album_count', this.selectedCount, this.selectedCount) 49700aff185Sopenharmony_ci : $r('app.string.move_to_album'); 49800aff185Sopenharmony_ci } else if (Action.ADD.equals(action)) { 49900aff185Sopenharmony_ci textStr = this.isSelected 50000aff185Sopenharmony_ci ? $r('app.plural.add_to_album_count', this.selectedCount, this.selectedCount) 50100aff185Sopenharmony_ci : $r('app.string.add_to_album'); 50200aff185Sopenharmony_ci } 50300aff185Sopenharmony_ci return textStr; 50400aff185Sopenharmony_ci } 50500aff185Sopenharmony_ci 50600aff185Sopenharmony_ci // 获取最近删除中,待回收照片倒计天数 50700aff185Sopenharmony_ci private calculateRecycleDays(): void { 50800aff185Sopenharmony_ci let currentTimeSeconds: number = new Date().getTime() / 1000; 50900aff185Sopenharmony_ci let itemDateTrashed: number = this.item == null ? 0 : this.item.dateTrashed; 51000aff185Sopenharmony_ci let trashedDay = DateUtil.convertSecondsToDays(currentTimeSeconds - itemDateTrashed); 51100aff185Sopenharmony_ci Log.debug(TAG, `currentSec=${currentTimeSeconds}, trashedSec=${itemDateTrashed}, trashedDay=${trashedDay}`); 51200aff185Sopenharmony_ci if (trashedDay > Constants.RECYCLE_DAYS_MAX) { 51300aff185Sopenharmony_ci this.recycleDays = 0; 51400aff185Sopenharmony_ci } else if (trashedDay <= 0) { 51500aff185Sopenharmony_ci this.recycleDays = Constants.RECYCLE_DAYS_MAX - 1; 51600aff185Sopenharmony_ci } else { 51700aff185Sopenharmony_ci this.recycleDays = Number.parseInt((Constants.RECYCLE_DAYS_MAX - trashedDay) + ''); 51800aff185Sopenharmony_ci } 51900aff185Sopenharmony_ci } 52000aff185Sopenharmony_ci 52100aff185Sopenharmony_ci private requestFocus(keyName: string): void { 52200aff185Sopenharmony_ci if (AppStorage.get<string>('deviceType') == Constants.DEFAULT_DEVICE_TYPE) { 52300aff185Sopenharmony_ci return; 52400aff185Sopenharmony_ci } 52500aff185Sopenharmony_ci let positionUri = AppStorage.get<string>('focusPosition'); 52600aff185Sopenharmony_ci let isUpdate = AppStorage.get<boolean>('focusUpdate'); 52700aff185Sopenharmony_ci if (this.item !== null && isUpdate && positionUri === this.item.uri) { 52800aff185Sopenharmony_ci let ret: Boolean = focusControl.requestFocus(keyName + this.item.uri); 52900aff185Sopenharmony_ci if (ret !== true) { 53000aff185Sopenharmony_ci Log.error(TAG, `requestFocus${keyName + this.item.uri}, ret:${ret}`); 53100aff185Sopenharmony_ci } 53200aff185Sopenharmony_ci AppStorage.setOrCreate('focusUpdate', false); 53300aff185Sopenharmony_ci } 53400aff185Sopenharmony_ci } 53500aff185Sopenharmony_ci 53600aff185Sopenharmony_ci private openPhotoBrowser(): void { 53700aff185Sopenharmony_ci if (this.isSelectedMode) { 53800aff185Sopenharmony_ci this.selectStateChange(); 53900aff185Sopenharmony_ci } else { 54000aff185Sopenharmony_ci Log.info(TAG, 'item onClick loadBmp'); 54100aff185Sopenharmony_ci Log.info(TAG, 'onClick loadThumbnailUri' + this.imageThumbnail); 54200aff185Sopenharmony_ci this.updateGeometryTapInfo(); 54300aff185Sopenharmony_ci if (this.isThird) { 54400aff185Sopenharmony_ci this.broadCast.emit(BroadCastConstants.JUMP_THIRD_PHOTO_BROWSER, 54500aff185Sopenharmony_ci [this.pageName, this.item, this.geometryTapIndex, this.geometryTransitionString]); 54600aff185Sopenharmony_ci } else { 54700aff185Sopenharmony_ci this.broadCast.emit(BroadCastConstants.JUMP_PHOTO_BROWSER, 54800aff185Sopenharmony_ci [this.pageName, this.item, this.geometryTapIndex, this.geometryTransitionString]); 54900aff185Sopenharmony_ci } 55000aff185Sopenharmony_ci this.isEnteringPhoto = true; 55100aff185Sopenharmony_ci } 55200aff185Sopenharmony_ci } 55300aff185Sopenharmony_ci 55400aff185Sopenharmony_ci private handleKeyEvent(event: KeyEvent): void { 55500aff185Sopenharmony_ci if (KeyType.Up == event.type) { 55600aff185Sopenharmony_ci switch (event.keyCode) { 55700aff185Sopenharmony_ci case MultimodalInputManager.KEY_CODE_KEYBOARD_ENTER: 55800aff185Sopenharmony_ci let msg: Msg = { 55900aff185Sopenharmony_ci from: BigDataConstants.BY_KEYBOARD, 56000aff185Sopenharmony_ci } 56100aff185Sopenharmony_ci ReportToBigDataUtil.report(BigDataConstants.ENTER_PHOTO_BROWSER_WAY, msg); 56200aff185Sopenharmony_ci this.openPhotoBrowser(); 56300aff185Sopenharmony_ci break; 56400aff185Sopenharmony_ci case MultimodalInputManager.KEY_CODE_KEYBOARD_ESC: 56500aff185Sopenharmony_ci this.onMenuClicked && this.onMenuClicked(Action.BACK); 56600aff185Sopenharmony_ci break; 56700aff185Sopenharmony_ci default: 56800aff185Sopenharmony_ci Log.info(TAG, `on key event Up, default`); 56900aff185Sopenharmony_ci break; 57000aff185Sopenharmony_ci } 57100aff185Sopenharmony_ci } 57200aff185Sopenharmony_ci } 57300aff185Sopenharmony_ci 57400aff185Sopenharmony_ci private updateGeometryTapInfo(): void { 57500aff185Sopenharmony_ci this.geometryTapIndex = this.getPosition(); 57600aff185Sopenharmony_ci } 57700aff185Sopenharmony_ci 57800aff185Sopenharmony_ci private getPosition(): number { 57900aff185Sopenharmony_ci if (this.dataSource == null || this.item == null) { 58000aff185Sopenharmony_ci return 0; 58100aff185Sopenharmony_ci } 58200aff185Sopenharmony_ci return this.dataSource.getDataIndex(this.item) + this.dataSource.getGroupCountBeforeItem(this.item); 58300aff185Sopenharmony_ci } 58400aff185Sopenharmony_ci}