• 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 {
17  EventConstants,
18  localEventManager,
19  Log,
20  Trace,
21  CheckEmptyUtils,
22  windowManager,
23  SnapShotInfo,
24  CommonConstants
25} from '@ohos/common';
26import RecentMissionAppIcon from './RecentMissionAppIcon';
27import RecentMissionAppName from './RecentMissionAppName';
28import { RecentMissionsViewModel } from '../../viewmodel/RecentMissionsViewModel';
29import { RecentsStyleConstants } from '../../common/constants/RecentsStyleConstants';
30import { RecentMissionStartAppHandler } from './../RecentMissionStartAppHandler';
31import { BusinessError } from '@ohos.base';
32
33const TAG = 'Recent-RecentMissionCard';
34
35interface AppParams {
36  bundleName: string;
37  moduleName: string;
38  appIconId: number;
39  borderRadius?: number;
40  isSingleLayout?: boolean;
41  appIconSize?: number;
42  appIconHeight?: number;
43  position?: Position
44}
45
46/**
47 * Common card component for recent missions.
48 */
49@Component
50export default struct RecentMissionCard {
51  @Link isClickSubComponent: boolean;
52  @State missionId: number = 0;
53  @State appIconId: number = 0;
54  @State appLabelId: number = 0;
55  @State appName: string = '';
56  @State bundleName: string = '';
57  @State moduleName: string = '';
58  @State abilityName: string = '';
59  @State lockedState: boolean = false;
60  @State cardMargin: number = RecentsStyleConstants.SINGLE_LIST_LAYOUT_MARGIN;
61  @State cardLayoutWeight: number = RecentsStyleConstants.SINGLE_LIST_APP_INFO_LAYOUT_WEIGHT;
62  // recentImage default is Resource type, to avoid toolchain typeCheck
63  @State recentImage?: image.PixelMap = undefined;
64  private mIsSingleLayout: boolean = true;
65  private snapShotTime: string = '';
66  private mRecentMissionsViewModel?: RecentMissionsViewModel;
67  private mRecentMissionStartAppHandler?: RecentMissionStartAppHandler;
68  private mReleaseFlag = true;
69
70  aboutToAppear(): void {
71    Log.showInfo(TAG, 'aboutToAppear start');
72    // remove this if toolchain fix requireNApi bug
73    this.mReleaseFlag = false;
74    this.mRecentMissionsViewModel = RecentMissionsViewModel.getInstance();
75    this.mIsSingleLayout = this.mRecentMissionsViewModel.getRecentMissionsRowType() === 'single' ? true : false;
76    this.cardMargin = this.mRecentMissionsViewModel.getRecentMissionsRowType() === 'single' ?
77      RecentsStyleConstants.SINGLE_LIST_LAYOUT_MARGIN *
78      RecentsStyleConstants.DPI_RATIO : RecentsStyleConstants.DOUBLE_LIST_LAYOUT_MARGIN;
79    this.cardLayoutWeight = this.mRecentMissionsViewModel.getRecentMissionsRowType() === 'single' ?
80      RecentsStyleConstants.SINGLE_LIST_APP_INFO_LAYOUT_WEIGHT :
81    RecentsStyleConstants.DOUBLE_LIST_APP_INFO_LAYOUT_WEIGHT;
82    this.mRecentMissionsViewModel.getMissionSnapShot(this.missionId, this.recentMissionsSnapshotCallback);
83    this.mRecentMissionStartAppHandler = RecentMissionStartAppHandler.getInstance();
84  }
85
86  aboutToDisappear(): void {
87    Log.showInfo(TAG, `aboutToDisappear start ${this.missionId}`);
88    Log.showDebug(TAG, `typeof this.recentImage ${typeof this.recentImage}`);
89    this.mReleaseFlag = true;
90    // typeof Resource or pixelMap is Object
91    if (!CheckEmptyUtils.isEmpty(this.recentImage)) {
92      this.recentImage?.release().catch((err: BusinessError) => {
93        Log.showError(TAG, `image.PixelMap release err: ${JSON.stringify(err)}`);
94      })
95      Log.showInfo(TAG, `aboutToDisappear end ${this.missionId}`);
96    }
97  }
98
99  /**
100 * The callback of Recent missions snapshot.
101 *
102 * @param {number} missionId
103 * @param {any} snapShotInfo
104 */
105  recentMissionsSnapshotCallback = (missionId: number, snapShotInfo: SnapShotInfo): void => {
106    Log.showDebug(TAG, `recentMissionsSnapshotCallback missionId: ${this.missionId}`);
107    if (!this.mReleaseFlag && missionId === this.missionId) {
108      this.recentImage = snapShotInfo.snapShotImage;
109      let width = snapShotInfo.snapShotImageWidth;
110      let height = snapShotInfo.snapShotImageHeight;
111      Log.showDebug(TAG, `recentMissionsSnapshotCallback recentImage: ${JSON.stringify(this.recentImage)},
112        width: ${JSON.stringify(width)}, height: ${JSON.stringify(height)}`);
113    } else {
114      snapShotInfo.snapShotImage.release().catch((err: BusinessError) => {
115        Log.showError(TAG, `image.PixelMap release err :${JSON.stringify(err)}`)
116      })
117    }
118  }
119
120  build() {
121    Column() {
122      Row() {
123        Row() {
124          RecentMissionAppIcon({
125            iconSize: this.mIsSingleLayout ?
126              RecentsStyleConstants.SINGLE_LIST_DEFAULT_APP_ICON_SIZE * RecentsStyleConstants.DPI_RATIO :
127              RecentsStyleConstants.DOUBLE_LIST_DEFAULT_APP_ICON_SIZE,
128            appIcon: this.appIconId,
129            bundleName: this.bundleName,
130            moduleName: this.moduleName,
131            labelId: this.appLabelId,
132            useCache: false
133          })
134          RecentMissionAppName({
135            appName: this.appName,
136            nameSize: this.mIsSingleLayout ?
137              RecentsStyleConstants.DEFAULT_APP_NAME_SIZE * RecentsStyleConstants.DPI_RATIO :
138              RecentsStyleConstants.DEFAULT_APP_NAME_SIZE,
139            bundleName: this.bundleName,
140            moduleName: this.moduleName,
141            labelId: this.appLabelId,
142            nameMargin: this.cardMargin / 2
143          })
144        }
145        .layoutWeight(this.cardLayoutWeight)
146        .margin({ left: RecentsStyleConstants.SINGLE_LIST_APP_INFO_LEFT_MARGIN })
147
148        .onClick((event) => {
149          this.isClickSubComponent = true;
150          Log.showDebug(TAG, 'onClick start launcher ability');
151          localEventManager.sendLocalEventSticky(EventConstants.EVENT_OPEN_FOLDER_TO_CLOSE, null);
152          windowManager.destroyWindow(windowManager.FORM_MANAGER_WINDOW_NAME);
153          windowManager.destroyWindow(windowManager.FORM_SERVICE_WINDOW_NAME);
154          if (!windowManager.recentMode || !windowManager.isSplitWindowMode(windowManager.recentMode)) {
155            windowManager.hideWindow(windowManager.RECENT_WINDOW_NAME);
156          }
157          Trace.start(Trace.CORE_METHOD_START_APP_ANIMATION);
158          this.setStartAppInfo(event?.target?.area?.globalPosition);
159          RecentMissionsViewModel.getInstance().moveMissionToFront(this.missionId);
160        })
161        if (this.lockedState) {
162          Column() {
163            Image(RecentsStyleConstants.DEFAULT_LOCKED_IMAGE)
164              .width(this.mIsSingleLayout ?
165              RecentsStyleConstants.SINGLE_LIST_DEFAULT_APP_ICON_SIZE_NEW :
166                RecentsStyleConstants.DOUBLE_LIST_DEFAULT_APP_ICON_SIZE - 10)
167              .height(this.mIsSingleLayout ?
168              RecentsStyleConstants.SINGLE_LIST_DEFAULT_APP_ICON_SIZE_NEW :
169                RecentsStyleConstants.DOUBLE_LIST_DEFAULT_APP_ICON_SIZE - 10)
170              .margin({
171                right: this.mIsSingleLayout ? (RecentsStyleConstants.SINGLE_LIST_LOCKED_IMAGE_RIGHT_MARGIN) :
172                  (RecentsStyleConstants.DOUBLE_LIST_LOCKED_IMAGE_RIGHT_MARGIN)
173              })
174              .onClick((event) => {
175                this.isClickSubComponent = true;
176                Log.showDebug(TAG, `click set recent mission: ${this.missionId} Locked status: ${!this.lockedState}`);
177                RecentMissionsViewModel.getInstance().setRecentMissionLock(this.missionId,!this.lockedState);
178                this.setStartAppInfo(event?.target?.area?.globalPosition);
179                this.isClickSubComponent = false;
180              })
181          }
182        }
183      }
184      .margin({
185        top: this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_APP_INFO_TOP_MARGIN :
186        RecentsStyleConstants.DOUBLE_LIST_APP_INFO_BOTTOM_MARGIN,
187        bottom: this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_APP_INFO_BOTTOM_MARGIN :
188        RecentsStyleConstants.DOUBLE_LIST_APP_INFO_BOTTOM_MARGIN
189      })
190
191      Image(this.recentImage)
192        .objectFit(ImageFit.Fill)
193        .borderRadius(RecentsStyleConstants.RECENT_IMAGE_RADIUS)
194        .width(this.mIsSingleLayout ?
195          RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH :
196          RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH)
197        .height(this.mIsSingleLayout ?
198          RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_HEIGHT :
199          RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_HEIGHT)
200        .onClick((event) => {
201          this.isClickSubComponent = true;
202          Log.showDebug(TAG, 'onClick start launcher ability');
203          localEventManager.sendLocalEventSticky(EventConstants.EVENT_OPEN_FOLDER_TO_CLOSE, null);
204          windowManager.destroyWindow(windowManager.FORM_MANAGER_WINDOW_NAME);
205          windowManager.destroyWindow(windowManager.FORM_SERVICE_WINDOW_NAME);
206          if (!windowManager.recentMode || !windowManager.isSplitWindowMode(windowManager.recentMode)) {
207            windowManager.hideWindow(windowManager.RECENT_WINDOW_NAME);
208          }
209          Trace.start(Trace.CORE_METHOD_START_APP_ANIMATION);
210          this.setStartAppInfo(event?.target?.area?.globalPosition);
211          RecentMissionsViewModel.getInstance().moveMissionToFront(this.missionId);
212        })
213    }
214    .width(this.mIsSingleLayout ?
215      RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH :
216      RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH)
217    .height(this.mIsSingleLayout ?
218      RecentsStyleConstants.SINGLE_LIST_MISSION_HEIGHT :
219      RecentsStyleConstants.DOUBLE_LIST_MISSION_HEIGHT)
220    .backgroundColor(RecentsStyleConstants.DEFAULT_BG_COLOR)
221    .gesture(
222    PanGesture({ fingers: 1, direction: PanDirection.Vertical, distance: 5 })
223      .onActionEnd((e) => {
224        let offsetWidth = (this.mIsSingleLayout ?
225          RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH * RecentsStyleConstants.DPI_RATIO :
226          RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH) / 2;
227        if (e.offsetY < -50 && e.offsetX <= offsetWidth && -offsetWidth <= e.offsetX) {
228          RecentMissionsViewModel.getInstance().deleteRecentMission(false, this.missionId);
229        } else if (e.offsetY > 50 && e.offsetX <= offsetWidth && -offsetWidth <= e.offsetX) {
230          Log.showDebug(TAG, `gesture set recent mission: ${this.missionId} Locked status: ${!this.lockedState}`);
231          RecentMissionsViewModel.getInstance().setRecentMissionLock(this.missionId,!this.lockedState);
232        }
233      }))
234  }
235
236  /**
237   * set start app info
238   */
239  private setStartAppInfo(position?: Position) {
240    AppStorage.setOrCreate('startAppTypeFromPageDesktop', CommonConstants.OVERLAY_TYPE_APP_ICON);
241    let appParams: AppParams = {
242      bundleName: this.bundleName,
243      moduleName: this.moduleName,
244      appIconId: this.appIconId,
245      borderRadius: RecentsStyleConstants.RECENT_IMAGE_RADIUS,
246      isSingleLayout: this.mIsSingleLayout,
247      appIconSize:this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_APP_IMAGE_WIDTH :
248      RecentsStyleConstants.DOUBLE_LIST_APP_IMAGE_WIDTH,
249      appIconHeight: this.mIsSingleLayout ? RecentsStyleConstants.SINGLE_LIST_MISSION_HEIGHT :
250      RecentsStyleConstants.DOUBLE_LIST_MISSION_HEIGHT,
251      position: position
252    }
253    AppStorage.setOrCreate('startAppItemInfo', appParams);
254    this.mRecentMissionStartAppHandler?.setAppIconSize(appParams.appIconSize, appParams.appIconHeight);
255    this.mRecentMissionStartAppHandler?.setAppIconInfo();
256  }
257}