1/* 2 * Copyright (c) 2022-2025 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 prompt from '@ohos.promptAction'; 17import router from '@ohos.router'; 18import mediaQuery from '@ohos.mediaquery'; 19import photoAccessHelper from '@ohos.file.photoAccessHelper'; 20import dataSharePredicates from '@ohos.data.dataSharePredicates'; 21import Logger from '../data/Logger'; 22 23const TAG: string = 'ChoicePhoto'; 24 25interface ChiceBuilderParam { 26 backGround: string, 27 showNumber: number 28}; 29 30@Entry 31@Component 32export struct ChoicePhotos { 33 @State whichShow: Array<boolean> = [true, false]; 34 @State medias: Array<photoAccessHelper.PhotoAsset> = []; 35 @State choiceShow: Array<Resource> = [$r('app.string.choice_photo'), $r('app.string.choice_video')]; 36 @State taskShow: Array<Resource> = [$r('app.media.photo'), $r('app.media.video')]; 37 @State textShow: Array<Resource> = [$r('app.string.photograph'), $r('app.string.take_video')]; 38 @State isShowChoices: Array<boolean> = new Array(this.medias.length).fill(false); 39 @State @Watch('choiceChange') choiceMedias: Array<photoAccessHelper.PhotoAsset> = []; 40 @State mediaUris: Array<string> = []; 41 @State isChoice: boolean = false; 42 @State nextText: string = ''; 43 @State isLand: boolean = false; 44 private listener = mediaQuery.matchMediaSync('screen and (min-aspect-ratio: 1.5) or (orientation: landscape)'); 45 onLand = (mediaQueryResult: mediaQuery.MediaQueryResult) => { 46 if (mediaQueryResult.matches) { 47 this.isLand = true 48 } else { 49 this.isLand = false 50 } 51 }; 52 53 choiceChange() { 54 if (this.choiceMedias.length > 0) { 55 this.isChoice = true 56 } else { 57 this.isChoice = false 58 } 59 } 60 61 @Builder showChoiceBuild($$: ChiceBuilderParam) { 62 Column() { 63 Text($$.showNumber === 0 ? '' : `${$$.showNumber}`) 64 .id(`select${$$.showNumber}`) 65 .fontSize(14) 66 .fontColor(Color.White) 67 .height(20) 68 .margin({ top: 2 }) 69 } 70 .width(24) 71 .height(24) 72 .margin({ top: 6, right: 6 }) 73 .borderRadius(15) 74 .border({ width: 1, style: BorderStyle.Solid, color: Color.White }) 75 .backgroundColor($$.backGround) 76 } 77 78 async getFileAssetsFromType(mediaType: photoAccessHelper.PhotoType) { 79 Logger.info(TAG, `getFileAssetsFromType`); 80 let context = getContext(this); 81 let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); 82 let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates(); 83 predicates.equalTo('media_type', mediaType); 84 let fetchOptions: photoAccessHelper.FetchOptions = { 85 fetchColumns: ['date_added', 'duration'], 86 predicates: predicates 87 }; 88 89 try { 90 let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> = 91 await phAccessHelper.getAssets(fetchOptions); 92 Logger.info(TAG, 'fetchResult success'); 93 if (fetchResult !== undefined) { 94 Logger.info(TAG, `fetchFileResult = ${JSON.stringify(fetchResult)}, ${fetchResult.getCount()}`); 95 if (fetchResult.getCount() > 0) { 96 this.medias = await fetchResult.getAllObjects(); 97 Logger.info(TAG, `this.medias = ${JSON.stringify(this.medias)}`); 98 } 99 } 100 } catch (err) { 101 Logger.error(TAG, 'getAssets failed, message = ' + JSON.stringify(err)); 102 } 103 } 104 105 async convertResourceToString(resource: Resource) { 106 Logger.info(TAG, `convertResourceToString result = ${getContext(this).resourceManager.getStringSync(resource)}`); 107 return getContext(this).resourceManager.getStringSync(resource); 108 } 109 110 getMaxHeight(): ConstraintSizeOptions { 111 if (!this.isLand && this.isChoice) { 112 return { maxHeight: '64%' }; 113 } else if (!this.isLand && !this.isChoice) { 114 return { maxHeight: '75.5%' }; 115 } else if (this.isLand && this.isChoice) { 116 return { maxHeight: '60%' }; 117 } else if (this.isLand && !this.isChoice) { 118 return { maxHeight: '71%' }; 119 }else { 120 return {}; 121 } 122 } 123 124 async aboutToAppear() { 125 Logger.info(TAG, `aboutToAppear`); 126 this.listener.on('change', this.onLand); 127 this.nextText = await this.convertResourceToString($r('app.string.next')); 128 this.getFileAssetsFromType(photoAccessHelper.PhotoType.IMAGE); 129 } 130 131 build() { 132 Column() { 133 Row() { 134 Image($r('app.media.back')) 135 .width(44) 136 .height(24) 137 .objectFit(ImageFit.Contain) 138 .onClick(() => { 139 router.back() 140 }) 141 142 Row() { 143 Text($r('app.string.recently_added')) 144 .fontColor(Color.Black) 145 .fontSize(22) 146 .textAlign(TextAlign.Center) 147 Image($r('app.media.drop_down')) 148 .width(30) 149 .height(32) 150 .objectFit(ImageFit.Contain) 151 } 152 153 Button(`${this.nextText} ${this.isChoice ? `(${this.choiceMedias.length})` : ''}`) 154 .id('nextStep') 155 .fontSize(20) 156 .height(32) 157 .backgroundColor(this.isChoice === true ? '#E92F4F' : '#fffa8e8e') 158 .margin({ right: 10 }) 159 .borderRadius(20) 160 .onClick(() => { 161 if (this.isChoice === false) { 162 return 163 } 164 this.mediaUris = this.choiceMedias.map((item) => { 165 return item.uri 166 }) 167 router.pushUrl({ 168 url: 'pages/Index', 169 params: { mediaUris: this.mediaUris, isShowCamera: true } 170 171 }) 172 }) 173 } 174 .width('100%') 175 .height(35) 176 .padding({ left: 14 }) 177 .margin({ top: 20 }) 178 .justifyContent(FlexAlign.SpaceBetween) 179 180 Column() { 181 Row() { 182 ForEach(this.choiceShow, (item: Resource, index) => { 183 Column() { 184 Text(item) 185 .fontSize(20) 186 .fontWeight(500) 187 .fontColor(this.whichShow[index] === true ? '#0000000' : '#99182431') 188 .onClick(() => { 189 this.whichShow.fill(false) 190 this.whichShow[index] = true 191 this.medias = [] 192 if (index == 0) { 193 this.getFileAssetsFromType(photoAccessHelper.PhotoType.IMAGE); 194 } else { 195 prompt.showDialog({ message: $r('app.string.user_tip') }); 196 this.choiceMedias = []; 197 this.isShowChoices = new Array(this.medias.length).fill(false); 198 this.getFileAssetsFromType(photoAccessHelper.PhotoType.VIDEO); 199 } 200 }) 201 if (this.whichShow[index]) { 202 Divider() 203 .vertical(false) 204 .strokeWidth(3) 205 .color('#ffff0000') 206 .lineCap(LineCapStyle.Round) 207 .width('40%') 208 .margin({ top: 4 }) 209 } 210 } 211 .width('30%') 212 .id(`type${index}`) 213 }) 214 } 215 .margin({ top: 20 }) 216 } 217 218 Scroll() { 219 Column() { 220 Grid() { 221 ForEach(this.medias, (item: photoAccessHelper.PhotoAsset, index) => { 222 GridItem() { 223 Stack({ alignContent: Alignment.TopEnd }) { 224 Image(item.uri) 225 .id(`image${index + 1}`) 226 .width('100%') 227 .height('100%') 228 .borderRadius(10) 229 .objectFit(ImageFit.Fill) 230 if (this.isShowChoices[index]) { 231 this.showChoiceBuild({ backGround: '#fffc0303', showNumber: this.choiceMedias.indexOf(item) + 1 }); 232 } else { 233 this.showChoiceBuild({ backGround:'#ffb7b4b4', showNumber: 0 }); 234 } 235 } 236 .width('100%') 237 .height('100%') 238 .onClick(() => { 239 this.isShowChoices[index] = !this.isShowChoices[index] 240 if (this.isShowChoices[index]) { 241 if (this.choiceMedias.length > 5) { 242 prompt.showDialog({ message: $r('app.string.choice_number') }) 243 this.isShowChoices[index] = !this.isShowChoices[index] 244 return 245 } 246 this.choiceMedias.push(item) 247 } else { 248 if (this.choiceMedias.indexOf(item) != -1) { 249 this.choiceMedias.splice(this.choiceMedias.indexOf(item), 1) 250 } 251 } 252 }) 253 } 254 .aspectRatio(1) 255 }) 256 } 257 .columnsTemplate('1fr 1fr 1fr 1fr') 258 .columnsGap(8) 259 .rowsGap(8) 260 } 261 .height('100%') 262 .width('95%') 263 .margin({ top: 8 }) 264 } 265 .margin({ top: 20 }) 266 .width('100%') 267 .constraintSize(this.getMaxHeight()) 268 .backgroundColor('#fff5f3f3') 269 270 if (this.isChoice) { 271 Grid() { 272 ForEach(this.choiceMedias, (item: photoAccessHelper.PhotoAsset, index) => { 273 GridItem() { 274 Stack({ alignContent: Alignment.TopEnd }) { 275 Image(item.uri) 276 .id(`selected${index + 1}`) 277 .width('100%') 278 .height(70) 279 .borderRadius(10) 280 Image($r('app.media.delete')) 281 .id(`deleteImage${index + 1}`) 282 .width(20) 283 .height(20) 284 .margin({ top: 5, right: 5 }) 285 .onClick(() => { 286 for (let i = 0;i < this.medias.length; i++) { 287 if (this.medias[i] === this.choiceMedias[index]) { 288 this.isShowChoices[i] = false 289 } 290 } 291 this.choiceMedias.splice(index, 1) 292 }) 293 } 294 .width('100%') 295 } 296 }, (item: photoAccessHelper.PhotoAsset) => item.uri ) 297 } 298 .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr') 299 .columnsGap(8) 300 .rowsGap(8) 301 .margin({ top: 8 }) 302 .width('95%') 303 .height(70) 304 305 Divider() 306 .vertical(false) 307 .strokeWidth(1) 308 .color('#ffd9d5d6') 309 .lineCap(LineCapStyle.Round) 310 .width('100%') 311 .margin({ top: 8 }) 312 } 313 314 Row() { 315 ForEach(this.taskShow, (item: Resource, index) => { 316 Column() { 317 Image(item) 318 .width(30) 319 .height(30) 320 321 Text(this.textShow[index]) 322 .fontSize(14) 323 .fontColor('#99182431') 324 .margin({ top: 2 }) 325 } 326 .width('50%') 327 }) 328 } 329 .margin({ top: 8 }) 330 } 331 } 332} 333