• 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 = RecentsStyleConstants.DEFAULT_APP_IMAGE;
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    && JSON.stringify(this.recentImage) != JSON.stringify(RecentsStyleConstants.DEFAULT_APP_IMAGE)) {
75      this.recentImage.release().catch((err) => {
76        Log.showError(TAG, `image.PixelMap release err: ${err}`);
77      })
78      Log.showInfo(TAG, `aboutToDisappear end ${this.missionId}`);
79    }
80  }
81
82  /**
83 * The callback of Recent missions snapshot.
84 *
85 * @param {number} missionId
86 * @param {any} snapShotInfo
87 */
88  recentMissionsSnapshotCallback(missionId: number, snapShotInfo: SnapShotInfo): void {
89    Log.showDebug(TAG, `recentMissionsSnapshotCallback missionId: ${this.missionId}`);
90    if (!this.mReleaseFlag && missionId === this.missionId) {
91      this.recentImage = snapShotInfo.snapShotImage;
92      let width = snapShotInfo.snapShotImageWidth;
93      let height = snapShotInfo.snapShotImageHeight;
94      Log.showDebug(TAG, `recentMissionsSnapshotCallback recentImage: ${JSON.stringify(this.recentImage)},
95        width: ${JSON.stringify(width)}, height: ${JSON.stringify(height)}`);
96    } else {
97      snapShotInfo.snapShotImage.release().catch((err) => {
98        Log.showError(TAG, `image.PixelMap release err :${err}`)
99      })
100    }
101  }
102
103  build() {
104    Column() {
105      Row() {
106        Row() {
107          RecentMissionAppIcon({
108            iconSize: this.mIsSingleLayout ?
109              RecentsStyleConstants.SINGLE_LIST_DEFAULT_APP_ICON_SIZE * RecentsStyleConstants.DPI_RATIO :
110              RecentsStyleConstants.DOUBLE_LIST_DEFAULT_APP_ICON_SIZE,
111            appIcon: this.appIconId,
112            bundleName: this.bundleName,
113            moduleName: this.moduleName,
114            labelId: this.appLabelId,
115            useCache: false
116          })
117          RecentMissionAppName({
118            appName: this.appName,
119            nameSize: this.mIsSingleLayout ?
120              RecentsStyleConstants.DEFAULT_APP_NAME_SIZE * RecentsStyleConstants.DPI_RATIO :
121              RecentsStyleConstants.DEFAULT_APP_NAME_SIZE,
122            bundleName: this.bundleName,
123            moduleName: this.moduleName,
124            labelId: this.appLabelId,
125            nameMargin: this.cardMargin / 2
126          })
127        }
128        .layoutWeight(this.cardLayoutWeight)
129        .margin({ left: RecentsStyleConstants.SINGLE_LIST_APP_INFO_LEFT_MARGIN })
130
131        .onClick((event) => {
132          this.setStartAppInfo(event?.target?.area?.globalPosition);
133        })
134        Column() {
135          Image(RecentsStyleConstants.DEFAULT_LOCKED_IMAGE)
136            .visibility(this.lockedState ? Visibility.Visible : Visibility.Hidden)
137            .width(this.mIsSingleLayout ?
138              RecentsStyleConstants.SINGLE_LIST_DEFAULT_APP_ICON_SIZE_NEW :
139              RecentsStyleConstants.DOUBLE_LIST_DEFAULT_APP_ICON_SIZE - 10)
140            .height(this.mIsSingleLayout ?
141              RecentsStyleConstants.SINGLE_LIST_DEFAULT_APP_ICON_SIZE_NEW :
142              RecentsStyleConstants.DOUBLE_LIST_DEFAULT_APP_ICON_SIZE - 10)
143            .margin({
144              right: this.mIsSingleLayout ? (RecentsStyleConstants.SINGLE_LIST_LOCKED_IMAGE_RIGHT_MARGIN) : (RecentsStyleConstants.DOUBLE_LIST_LOCKED_IMAGE_RIGHT_MARGIN)
145            })
146            .onClick((event) => {
147              this.isClickSubComponent = true;
148              Log.showDebug(TAG, `click set recent mission: ${this.missionId} Locked status: ${!this.lockedState}`);
149              this.mRecentMissionsViewModel.setRecentMissionLock(this.missionId,!this.lockedState);
150              this.setStartAppInfo(event?.target?.area?.globalPosition);
151              this.isClickSubComponent = false;
152            })
153        }
154      }
155      .margin({
156        top: this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_APP_INFO_TOP_MARGIN : RecentsStyleConstants.DOUBLE_LIST_APP_INFO_BOTTOM_MARGIN,
157        bottom: this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_APP_INFO_BOTTOM_MARGIN : RecentsStyleConstants.DOUBLE_LIST_APP_INFO_BOTTOM_MARGIN
158      })
159
160      Image(this.recentImage)
161        .alt(RecentsStyleConstants.DEFAULT_APP_IMAGE)
162        .objectFit(ImageFit.Fill)
163        .borderRadius(RecentsStyleConstants.RECENT_IMAGE_RADIUS)
164        .width(this.mIsSingleLayout ?
165          RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH :
166          RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH)
167        .height(this.mIsSingleLayout ?
168          RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_HEIGHT :
169          RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_HEIGHT)
170        .onClick((event) => {
171          this.isClickSubComponent = true;
172          Log.showDebug(TAG, 'onClick start launcher ability');
173          if (!globalThis.recentMode || !windowManager.isSplitWindowMode(globalThis.recentMode)) {
174            windowManager.hideWindow(windowManager.RECENT_WINDOW_NAME);
175          }
176          Trace.start(Trace.CORE_METHOD_START_APP_ANIMATION);
177          this.setStartAppInfo(event?.target?.area?.globalPosition);
178          this.mRecentMissionsViewModel.moveMissionToFront(this.missionId);
179        })
180    }
181    .width(this.mIsSingleLayout ?
182      RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH :
183      RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH)
184    .height(this.mIsSingleLayout ?
185      RecentsStyleConstants.SINGLE_LIST_MISSION_HEIGHT :
186      RecentsStyleConstants.DOUBLE_LIST_MISSION_HEIGHT)
187    .backgroundColor(RecentsStyleConstants.DEFAULT_BG_COLOR)
188    .gesture(
189    PanGesture({ fingers: 1, direction: PanDirection.Vertical, distance: 5 })
190      .onActionEnd((e) => {
191        let offsetWidth = (this.mIsSingleLayout ?
192          RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH * RecentsStyleConstants.DPI_RATIO :
193          RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH) / 2;
194        if (e.offsetY < -50 && e.offsetX <= offsetWidth && -offsetWidth <= e.offsetX) {
195          this.mRecentMissionsViewModel.deleteRecentMission(false, this.missionId);
196        } else if (e.offsetY > 50 && e.offsetX <= offsetWidth && -offsetWidth <= e.offsetX) {
197          Log.showDebug(TAG, `gesture set recent mission: ${this.missionId} Locked status: ${!this.lockedState}`);
198          this.mRecentMissionsViewModel.setRecentMissionLock(this.missionId,!this.lockedState);
199        }
200      }))
201  }
202
203  /**
204   * set start app info
205   */
206  private setStartAppInfo(position) {
207    AppStorage.SetOrCreate('startAppTypeFromPageDesktop', CommonConstants.OVERLAY_TYPE_APP_ICON);
208    let appParams = {
209      bundleName: this.bundleName,
210      moduleName: this.moduleName,
211      appIconId: this.appIconId,
212      borderRadius: RecentsStyleConstants.RECENT_IMAGE_RADIUS,
213      isSingleLayout: this.mIsSingleLayout,
214      appIconSize:this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH : RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH,
215      appIconHeight: this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_MISSION_HEIGHT : RecentsStyleConstants.DOUBLE_LIST_MISSION_HEIGHT,
216      position:position
217    }
218    AppStorage.SetOrCreate('startAppItemInfo', appParams);
219    this.mRecentMissionStartAppHandler.setAppIconSize(appParams.appIconSize, appParams.appIconHeight);
220    this.mRecentMissionStartAppHandler.setAppIconInfo();
221  }
222}