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}