• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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