1/* 2 * Copyright (c) 2022-2023 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 */ 15 16import type { AsyncCallback } from '../../model/common/AsyncCallback'; 17import { Log } from '../../utils/Log'; 18import type { MenuOperationCallback } from './MenuOperationCallback'; 19import type { MenuOperation } from './MenuOperation'; 20import { MenuContext } from './MenuContext'; 21import { BroadCastConstants } from '../../model/common/BroadCastConstants'; 22import { BrowserDataFactory } from '../../interface/BrowserDataFactory'; 23import { TraceControllerUtils } from '../../utils/TraceControllerUtils'; 24import type { FileAsset } from '../../access/UserFileManagerAccess'; 25 26const TAG: string = 'common_ProcessMenuOperation'; 27 28export class ProcessMenuOperation implements MenuOperation, AsyncCallback<String[]>, MenuOperationCallback { 29 // Number of data operated in a batch 30 readonly BATCH_SIZE: number = 1; 31 32 // Maximum progress 33 readonly MAX_PROGRESS: number = 100; 34 menuContext: MenuContext; 35 uris: string[]; 36 count: number; 37 onOperationEnd: Function; 38 39 // Total batches operated 40 totalBatches: number; 41 42 // Currently operated batch 43 currentBatch: number = 0; 44 successBatch: number = 0; 45 isCancelled: boolean = false; 46 startTime: number; 47 isPause: boolean = false; 48 isError: boolean = false; 49 requestTime: number; 50 51 constructor(menuContext: MenuContext) { 52 this.menuContext = menuContext; 53 this.requestTime = Date.now(); 54 } 55 56 doAction(): void { 57 58 } 59 60 // Asynchronous callback for getSelection 61 callback(uris: string[]): void { 62 63 } 64 65 onCompleted(): void { 66 Log.info(TAG, `onCompleted ${this.isPause}`); 67 this.successBatch++; 68 if (!this.isPause) { 69 this.cyclicOperation(); 70 } 71 } 72 73 onError(): void { 74 Log.error(TAG, `Operate the ${this.currentBatch} batch data error, total ${this.totalBatches} batches`); 75 this.isError = true; 76 this.cyclicOperation(); 77 } 78 79 // Operate a batch of data 80 requestOneBatchOperation(): void { 81 82 } 83 84 // Start processing operation 85 processOperation(): void { 86 Log.info(TAG, 'processOperation start'); 87 TraceControllerUtils.startTraceWithTaskId('ProgressOperation', this.requestTime); 88 if (this.uris == null) { 89 Log.error(TAG, 'Invalid callback data, uris is null!'); 90 return; 91 } 92 let length = this.uris.length; 93 Log.info(TAG, `selected count: ${this.count}, uris's length: ${length}`); 94 // Batch deletion 95 this.totalBatches = Math.floor(length / this.BATCH_SIZE) + ((length % this.BATCH_SIZE) ? 1 : 0); 96 Log.info(TAG, `The count to be operate is ${length}, operate in ${this.totalBatches} batches`); 97 if (this.isCancelled) { 98 return; 99 } 100 this.startTime = Date.now(); 101 this.requestOneBatchOperation(); 102 } 103 104 // Batch circular deletion 105 cyclicOperation() { 106 Log.info(TAG, 'cyclicOperation'); 107 this.menuContext.broadCast.emit(BroadCastConstants.UPDATE_PROGRESS, 108 [this.getExpectProgress(), this.currentBatch * this.BATCH_SIZE]); 109 110 if (this.isCancelled) { 111 this.isCancelled = false; 112 } 113 114 if (this.currentBatch >= this.totalBatches) { 115 this.onProcessDone(); 116 } else { 117 this.requestOneBatchOperation(); 118 } 119 } 120 121 onProcessDone(): void { 122 this.menuContext.broadCast.emit(BroadCastConstants.UPDATE_PROGRESS, [100]); 123 if (this.startTime != null) { 124 let operateCount = this.currentBatch >= this.totalBatches ? this.count : this.currentBatch * this.BATCH_SIZE; 125 let costTime = Date.now() - this.startTime; 126 Log.debug(TAG, `process data operate done, operate ${operateCount} items, cost time ${costTime} ms,\ 127 average ${(costTime / operateCount)} .`); 128 } 129 TraceControllerUtils.finishTraceWithTaskId('ProgressOperation', this.requestTime); 130 this.onOperationEnd && this.onOperationEnd(this.isError, this.successBatch, this.count); 131 } 132 133 // Operate cancel callback 134 onOperateCancelled(): void { 135 Log.info(TAG, 'Operate Cancel'); 136 this.isCancelled = true; 137 this.onProcessDone(); 138 } 139 140 // Operate cancel callback 141 onOperatePause(): void { 142 Log.info(TAG, 'Operate Pause'); 143 this.isPause = true; 144 } 145 146 // Calculate the operation progress according to the batch 147 getExpectProgress(): number { 148 Log.info(TAG, 'getExpectProgress'); 149 let progress = Math.min( 150 Math.floor(this.MAX_PROGRESS * this.currentBatch * this.BATCH_SIZE / this.count), this.MAX_PROGRESS); 151 return progress; 152 } 153 154 async getFileAddOrMoveInfo(fileUri: string): Promise<FileAsset> { 155 Log.debug(TAG, `getFileCopyOrMoveInfo start uri: ${JSON.stringify(fileUri)}`); 156 let dataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_PHOTO); 157 let fileAsset = await dataImpl.getDataByUri(fileUri); 158 return fileAsset; 159 } 160}