• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15import image from '@ohos.multimedia.image';
16import { Log } from '@ohos/common';
17import { Trace } from '@ohos/common';
18import { CheckEmptyUtils } from '@ohos/common';
19import { windowManager } from '@ohos/common';
20import { SnapShotInfo } from '@ohos/common';
21import { CommonConstants } from '@ohos/common';
22import RecentMissionAppIcon from './RecentMissionAppIcon';
23import RecentMissionAppName from './RecentMissionAppName';
24import { RecentMissionsViewModel } from '../../viewmodel/RecentMissionsViewModel';
25import { RecentsStyleConstants } from '../../common/constants/RecentsStyleConstants';
26import { RecentMissionStartAppHandler } from './../RecentMissionStartAppHandler';
27
28const TAG = 'Recent-RecentMissionCard';
29
30/**
31 * Common card component for recent missions.
32 */
33@Component
34export default struct RecentMissionCard {
35  @Link isClickSubComponent: boolean;
36  @State missionId: number = 0;
37  @State appIconId: string = '';
38  @State appLabelId: string = '';
39  @State appName: string = '';
40  @State bundleName: string = '';
41  @State moduleName: string = '';
42  @State abilityName: string = '';
43  @State lockedState: boolean = false;
44  @State cardMargin: number = RecentsStyleConstants.SINGLE_LIST_LAYOUT_MARGIN;
45  @State cardLayoutWeight: number = RecentsStyleConstants.SINGLE_LIST_APP_INFO_LAYOUT_WEIGHT;
46  // recentImage default is Resource type, to avoid toolchain typeCheck
47  @State recentImage: any = '';
48  private mIsSingleLayout: boolean = true;
49  private snapShotTime: string = '';
50  private mRecentMissionsViewModel: RecentMissionsViewModel;
51  private mRecentMissionStartAppHandler: RecentMissionStartAppHandler;
52  private mReleaseFlag = true;
53
54  aboutToAppear(): void {
55    Log.showInfo(TAG, 'aboutToAppear start');
56    // remove this if toolchain fix requireNApi bug
57    this.mReleaseFlag = false;
58    this.mRecentMissionsViewModel = RecentMissionsViewModel.getInstance();
59    this.mIsSingleLayout = this.mRecentMissionsViewModel.getRecentMissionsRowType() === 'single' ? true : false;
60    this.cardMargin = this.mRecentMissionsViewModel.getRecentMissionsRowType() === 'single' ?
61      RecentsStyleConstants.SINGLE_LIST_LAYOUT_MARGIN * RecentsStyleConstants.DPI_RATIO : RecentsStyleConstants.DOUBLE_LIST_LAYOUT_MARGIN;
62    this.cardLayoutWeight = this.mRecentMissionsViewModel.getRecentMissionsRowType() === 'single' ?
63      RecentsStyleConstants.SINGLE_LIST_APP_INFO_LAYOUT_WEIGHT : RecentsStyleConstants.DOUBLE_LIST_APP_INFO_LAYOUT_WEIGHT;
64    this.mRecentMissionsViewModel.getMissionSnapShot(this.missionId, this.recentMissionsSnapshotCallback.bind(this));
65    this.mRecentMissionStartAppHandler = RecentMissionStartAppHandler.getInstance();
66  }
67
68  aboutToDisappear(): void {
69    Log.showInfo(TAG, `aboutToDisappear start ${this.missionId}`);
70    Log.showDebug(TAG, `typeof this.recentImage ${typeof this.recentImage}`);
71    this.mReleaseFlag = true;
72    // typeof Resource or pixelMap is Object
73    if (!CheckEmptyUtils.isEmpty(this.recentImage)) {
74      this.recentImage.release().catch((err) => {
75        Log.showError(TAG, `image.PixelMap release err: ${err}`);
76      })
77      Log.showInfo(TAG, `aboutToDisappear end ${this.missionId}`);
78    }
79  }
80
81  /**
82 * The callback of Recent missions snapshot.
83 *
84 * @param {number} missionId
85 * @param {any} snapShotInfo
86 */
87  recentMissionsSnapshotCallback(missionId: number, snapShotInfo: SnapShotInfo): void {
88    Log.showDebug(TAG, `recentMissionsSnapshotCallback missionId: ${this.missionId}`);
89    if (!this.mReleaseFlag && missionId === this.missionId) {
90      this.recentImage = snapShotInfo.snapShotImage;
91      let width = snapShotInfo.snapShotImageWidth;
92      let height = snapShotInfo.snapShotImageHeight;
93      Log.showDebug(TAG, `recentMissionsSnapshotCallback recentImage: ${JSON.stringify(this.recentImage)},
94        width: ${JSON.stringify(width)}, height: ${JSON.stringify(height)}`);
95    } else {
96      snapShotInfo.snapShotImage.release().catch((err) => {
97        Log.showError(TAG, `image.PixelMap release err :${err}`)
98      })
99    }
100  }
101
102  build() {
103    Column() {
104      Row() {
105        Row() {
106          RecentMissionAppIcon({
107            iconSize: this.mIsSingleLayout ?
108              RecentsStyleConstants.SINGLE_LIST_DEFAULT_APP_ICON_SIZE * RecentsStyleConstants.DPI_RATIO :
109              RecentsStyleConstants.DOUBLE_LIST_DEFAULT_APP_ICON_SIZE,
110            appIcon: this.appIconId,
111            bundleName: this.bundleName,
112            moduleName: this.moduleName,
113            labelId: this.appLabelId,
114            useCache: false
115          })
116          RecentMissionAppName({
117            appName: this.appName,
118            nameSize: this.mIsSingleLayout ?
119              RecentsStyleConstants.DEFAULT_APP_NAME_SIZE * RecentsStyleConstants.DPI_RATIO :
120              RecentsStyleConstants.DEFAULT_APP_NAME_SIZE,
121            bundleName: this.bundleName,
122            moduleName: this.moduleName,
123            labelId: this.appLabelId,
124            nameMargin: this.cardMargin / 2
125          })
126        }
127        .layoutWeight(this.cardLayoutWeight)
128        .margin({ left: RecentsStyleConstants.SINGLE_LIST_APP_INFO_LEFT_MARGIN })
129
130        .onClick((event) => {
131          this.setStartAppInfo(event?.target?.area?.globalPosition);
132        })
133        Column() {
134          Image(RecentsStyleConstants.DEFAULT_LOCKED_IMAGE)
135            .visibility(this.lockedState ? Visibility.Visible : Visibility.Hidden)
136            .width(this.mIsSingleLayout ?
137              RecentsStyleConstants.SINGLE_LIST_DEFAULT_APP_ICON_SIZE_NEW :
138              RecentsStyleConstants.DOUBLE_LIST_DEFAULT_APP_ICON_SIZE - 10)
139            .height(this.mIsSingleLayout ?
140              RecentsStyleConstants.SINGLE_LIST_DEFAULT_APP_ICON_SIZE_NEW :
141              RecentsStyleConstants.DOUBLE_LIST_DEFAULT_APP_ICON_SIZE - 10)
142            .margin({
143              right: this.mIsSingleLayout ? (RecentsStyleConstants.SINGLE_LIST_LOCKED_IMAGE_RIGHT_MARGIN) : (RecentsStyleConstants.DOUBLE_LIST_LOCKED_IMAGE_RIGHT_MARGIN)
144            })
145            .onClick((event) => {
146              this.isClickSubComponent = true;
147              Log.showDebug(TAG, `click set recent mission: ${this.missionId} Locked status: ${!this.lockedState}`);
148              this.mRecentMissionsViewModel.setRecentMissionLock(this.missionId,!this.lockedState);
149              this.setStartAppInfo(event?.target?.area?.globalPosition);
150              this.isClickSubComponent = false;
151            })
152        }
153      }
154      .margin({
155        top: this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_APP_INFO_TOP_MARGIN : RecentsStyleConstants.DOUBLE_LIST_APP_INFO_BOTTOM_MARGIN,
156        bottom: this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_APP_INFO_BOTTOM_MARGIN : RecentsStyleConstants.DOUBLE_LIST_APP_INFO_BOTTOM_MARGIN
157      })
158
159      Image(this.recentImage)
160        .objectFit(ImageFit.Fill)
161        .borderRadius(RecentsStyleConstants.RECENT_IMAGE_RADIUS)
162        .width(this.mIsSingleLayout ?
163          RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH :
164          RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH)
165        .height(this.mIsSingleLayout ?
166          RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_HEIGHT :
167          RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_HEIGHT)
168        .onClick((event) => {
169          this.isClickSubComponent = true;
170          Log.showDebug(TAG, 'onClick start launcher ability');
171          if (!globalThis.recentMode || !windowManager.isSplitWindowMode(globalThis.recentMode)) {
172            windowManager.hideWindow(windowManager.RECENT_WINDOW_NAME);
173          }
174          Trace.start(Trace.CORE_METHOD_START_APP_ANIMATION);
175          this.setStartAppInfo(event?.target?.area?.globalPosition);
176          this.mRecentMissionsViewModel.moveMissionToFront(this.missionId);
177        })
178    }
179    .width(this.mIsSingleLayout ?
180      RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH :
181      RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH)
182    .height(this.mIsSingleLayout ?
183      RecentsStyleConstants.SINGLE_LIST_MISSION_HEIGHT :
184      RecentsStyleConstants.DOUBLE_LIST_MISSION_HEIGHT)
185    .backgroundColor(RecentsStyleConstants.DEFAULT_BG_COLOR)
186    .gesture(
187    PanGesture({ fingers: 1, direction: PanDirection.Vertical, distance: 5 })
188      .onActionEnd((e) => {
189        let offsetWidth = (this.mIsSingleLayout ?
190          RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH * RecentsStyleConstants.DPI_RATIO :
191          RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH) / 2;
192        if (e.offsetY < -50 && e.offsetX <= offsetWidth && -offsetWidth <= e.offsetX) {
193          this.mRecentMissionsViewModel.deleteRecentMission(false, this.missionId);
194        } else if (e.offsetY > 50 && e.offsetX <= offsetWidth && -offsetWidth <= e.offsetX) {
195          Log.showDebug(TAG, `gesture set recent mission: ${this.missionId} Locked status: ${!this.lockedState}`);
196          this.mRecentMissionsViewModel.setRecentMissionLock(this.missionId,!this.lockedState);
197        }
198      }))
199  }
200
201  /**
202   * set start app info
203   */
204  private setStartAppInfo(position) {
205    AppStorage.SetOrCreate('startAppTypeFromPageDesktop', CommonConstants.OVERLAY_TYPE_APP_ICON);
206    let appParams = {
207      bundleName: this.bundleName,
208      moduleName: this.moduleName,
209      appIconId: this.appIconId,
210      borderRadius: RecentsStyleConstants.RECENT_IMAGE_RADIUS,
211      isSingleLayout: this.mIsSingleLayout,
212      appIconSize:this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH : RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH,
213      appIconHeight: this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_MISSION_HEIGHT : RecentsStyleConstants.DOUBLE_LIST_MISSION_HEIGHT,
214      position:position
215    }
216    AppStorage.SetOrCreate('startAppItemInfo', appParams);
217    this.mRecentMissionStartAppHandler.setAppIconSize(appParams.appIconSize, appParams.appIconHeight);
218    this.mRecentMissionStartAppHandler.setAppIconInfo();
219  }
220}