1/* 2 * Copyright (c) 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 { Log } from '../utils/Log'; 16import MediaLib from '@ohos.multimedia.mediaLibrary'; 17import { ViewType } from '../data/ViewType'; 18import mediaModel from '../model/MediaModel'; 19import { MediaConstants } from '../constants/MediaConstants'; 20import { setOrientation } from '../helper/MediaDataHelper'; 21import selectManager from '../manager/SelectManager'; 22import { ItemDataSource } from '../vm/ItemDataSource' 23const TAG = "MediaDataItem" 24 25const STATUS_UNDEFINED = -1 26const STATUS_FALSE = 0 27const STATUS_TRUE = 1 28 29export class MediaDataItem { 30 readonly viewType = ViewType.ITEM 31 readonly hashIndex: number 32 index: number 33 dateAdded: number 34 dateModified: number 35 dateTaken: number 36 status: number = MediaConstants.UNDEFINED 37 isSelect: boolean = false 38 id: number 39 uri: string 40 orientation: number 41 duration: number 42 size: number 43 width: number; // width changed by orientation 44 height: number; // height changed by orientation 45 imgWidth: number; // may be smaller than width, as width is too large 46 imgHeight: number; // may be smaller than height, as height is too large 47 path: string 48 title: string 49 displayName: string 50 mediaType: MediaLib.MediaType 51 favouriteStatus: number = STATUS_UNDEFINED 52 canRotate: number = STATUS_UNDEFINED 53 selections: string = "" 54 selectionArgs: Array<string> = new Array() 55 deviceId: string = '' 56 57 constructor(selections: string, selectionArgs: Array<string>, deviceId: string, index: number) { 58 this.selections = selections 59 this.selectionArgs = selectionArgs 60 this.deviceId = deviceId 61 this.hashIndex = index 62 this.index = index 63 } 64 65 getHashCode(): string { 66 //时间线界面角度,收藏状态变更,都需要刷新界面;大图浏览界面角度变更,需要刷新界面 67 return this.status == MediaConstants.UNDEFINED ? 68 `${this.hashIndex}` : 69 `${this.uri}${this.favouriteStatus} ${this.orientation} ${this.isSelect}` 70 } 71 72 async loadFileAsset(): Promise<MediaLib.FileAsset> { 73 let fetchOption: MediaLib.MediaFetchOptions 74 if (this.status == MediaConstants.UNDEFINED) { 75 fetchOption = { 76 selections: this.selections, 77 selectionArgs: this.selectionArgs, 78 order: `date_added DESC LIMIT ${this.index},1` 79 }; 80 } else { 81 fetchOption = { 82 selections: `${MediaLib.FileKey.ID} = ?`, 83 selectionArgs: [this.id.toString()], 84 order: `date_added DESC` 85 } 86 } 87 if (this.deviceId.length > 0) { 88 fetchOption['networkId'] = this.deviceId 89 } 90 return (await mediaModel.getAllCommonMediaItem(fetchOption, false)).fileAsset 91 } 92 93 isLoad():boolean { 94 if (this.status > MediaConstants.UNDEFINED) { 95 return true 96 } 97 return false 98 } 99 100 async load(isForce: boolean): Promise<void> { 101 Log.info(TAG, `load ${this.status}`) 102 if (this.status > (isForce ? MediaConstants.PART_LOADED : MediaConstants.UNDEFINED)) { 103 return 104 } 105 let fileAsset = await this.loadFileAsset() 106 if (fileAsset) { 107 this.update(fileAsset) 108 } 109 return 110 } 111 112 update(fileAsset: MediaLib.FileAsset) { 113 this.id = fileAsset.id; 114 this.uri = fileAsset.uri; 115 this.orientation = fileAsset.orientation; 116 this.mediaType = fileAsset.mediaType; 117 this.duration = fileAsset.duration; 118 this.size = fileAsset.size; 119 if (this.orientation == MediaConstants.ROTATE_ONCE || this.orientation == MediaConstants.ROTATE_THIRD) { 120 this.width = fileAsset.height; 121 this.height = fileAsset.width; 122 } else { 123 this.width = fileAsset.width; 124 this.height = fileAsset.height; 125 } 126 this.imgWidth = this.width; 127 this.imgHeight = this.height; 128 this.path = fileAsset.relativePath; 129 this.title = fileAsset.title; 130 this.displayName = fileAsset.displayName; 131 this.dateAdded = fileAsset.dateAdded * 1000; 132 this.dateModified = fileAsset.dateModified * 1000; 133 this.dateTaken = fileAsset.dateTaken * 1000; 134 this.isSelect = selectManager.isSelect(this.uri, this.isSelect); 135 136 // may change 137 fileAsset.isFavorite().then((isFavor: boolean) => this.favouriteStatus = (isFavor) ? STATUS_TRUE : STATUS_FALSE); 138 139 if (this.width > 0 && this.height > 0) { 140 this.status = MediaConstants.LOADED; 141 } else { 142 this.status = MediaConstants.PART_LOADED; 143 } 144 } 145 146 getThumbnail(width: number, height: number): string { 147 Log.debug(TAG, `getThumbnail ${this.status}`); 148 if (this.status != MediaConstants.LOADED && this.status != MediaConstants.PART_LOADED) { 149 Log.warn(TAG, `getThumbnail fail as status: ${this.status}`); 150 return ""; 151 } 152 Log.debug(TAG, `this.uri ${this.uri}`); 153 return this.uri + `/thumbnail/${width}/${height}`; 154 } 155 156 getAlt(): Resource { 157 if (this.mediaType == MediaLib.MediaType.VIDEO) { 158 return $r('app.media.alt_video_placeholder'); 159 } else { 160 return $r('app.media.alt_placeholder'); 161 } 162 } 163 164 setSelect(isSelect: boolean) { 165 this.isSelect = isSelect; 166 selectManager.setSelect(this.uri, this.isSelect); 167 } 168 169 async onDelete(): Promise<boolean> { 170 try { 171 let fileAsset = await this.loadFileAsset(); 172 await fileAsset.trash(true); 173 selectManager.deleteSelect(this.uri); 174 this.status = MediaConstants.TRASHED; 175 return true; 176 } catch (err) { 177 Log.error(TAG, `onDelete ${this.index} error: ${JSON.stringify(err)}`); 178 return false; 179 } 180 } 181 182 isDeleted(): boolean { 183 return this.status == MediaConstants.TRASHED; 184 } 185 186 async isFavor(): Promise<boolean> { 187 if (this.favouriteStatus == STATUS_UNDEFINED) { 188 let fileAsset = await this.loadFileAsset(); 189 this.favouriteStatus = (await fileAsset.isFavorite()) ? STATUS_TRUE : STATUS_FALSE; 190 } 191 return this.favouriteStatus == STATUS_TRUE; 192 } 193 194 async setFavor(): Promise<boolean> { 195 let status = !(await this.isFavor()); 196 try { 197 let fileAsset = await this.loadFileAsset(); 198 await fileAsset.favorite(status); 199 await fileAsset.commitModify(); 200 this.favouriteStatus = status ? STATUS_TRUE : STATUS_FALSE; 201 return true; 202 } catch (err) { 203 return false; 204 } 205 } 206 207 async setOrientation(): Promise<void> { 208 let fileAsset = await this.loadFileAsset(); 209 this.orientation = (this.orientation + MediaConstants.ROTATE_ONCE) % MediaConstants.ROTATE_AROUND; 210 await setOrientation(fileAsset, this.orientation); 211 let tmp = this.width; 212 this.width = this.height; 213 this.height = tmp; 214 } 215 216 async setName(name: string): Promise<void> { 217 let fileAsset = await this.loadFileAsset(); 218 let displayName = fileAsset.displayName; 219 let index = displayName.lastIndexOf('.'); 220 displayName = name + displayName.slice(index); 221 222 this.displayName = displayName; 223 fileAsset.displayName = displayName; 224 225 this.title = name; 226 fileAsset.title = name;; 227 await fileAsset.commitModify(); 228 } 229}