• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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 router from '@ohos.router';
17import fs from '@ohos.file.fs';
18import common from '@ohos.app.ability.common';
19import picker from '@ohos.file.picker';
20import photoAccessHelper from '@ohos.file.photoAccessHelper';
21import image from '@ohos.multimedia.image';
22import Logger from '../utils/Logger';
23import CommonConstants from '../common/constants/CommonConstants';
24import { BusinessError } from '@ohos.base';
25import { LooperUtil } from '../utils/LooperUtil';
26
27const TAG = 'testTag_Notes: ';
28let context = getContext(this) as common.UIAbilityContext; //获取设备A&B UIAbilityContext信息
29let disPath: string = context.distributedFilesDir;
30//获取分布式目录的文件路径
31let filePath: string = disPath + '/picture.jpg';
32
33@Entry
34@Component
35struct Notes {
36  @State text: string = '';
37  @State img: string = 'app.media.pic_image';
38  @StorageLink('isContinuation') isContinuation: boolean = false;
39  @StorageLink('isSelectImg') isSelectImg: boolean = false;
40  @StorageLink('inputText') inputText: string = '';
41  @StorageLink('inputTextArea') inputTextArea: string = '';
42  @StorageLink('imgStr') imgStr: string = 'app.media.pic_image';
43  @StorageLink('ability_isON') stoLink_ability_isON: boolean = true;
44  controller: TextAreaController = new TextAreaController();
45  @State num: number = 0;
46  @State image1: PixelMap | null = null; // 图一展示照片(选择或流转)
47  @State image2: Object = new Object; // 图二展示照片(选择或流转)
48  @StorageLink('imgIsVisible1') imgIsVisible1: boolean = true;
49  @StorageLink('imgIsVisible2') imgIsVisible2: boolean = true;
50  @State showSubMenus: boolean = false;
51  @State jpgStr: string = '';
52  @State uris: Array<string> = []; // 用于接受 PhotoViewPicker选择图片1的返回的uri(分布式文件方式)
53  @State uris2: Array<string> = []; // 用于接受 PhotoViewPicker选择图片2的返回的uri(分布式文件方式)
54  @State fileName: string = '';
55  @State readLenAtSink: number = 0;
56  private imgArray: Resource[] = [
57  $r('app.media.pic_image'),
58  $r('app.media.img_08'),
59  $r('app.media.img_07')
60  ]
61
62  // 从图库中选择图片
63  async choosePictureFile() {
64    try {
65      let photoSelectOptions = new picker.PhotoSelectOptions();
66      photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
67      photoSelectOptions.maxSelectNumber = 1;
68      let photoPicker = new picker.PhotoViewPicker();
69      photoPicker.select(photoSelectOptions).then((photoSelectResult) => {
70        if (!photoSelectResult) {
71          Logger.error(TAG, 'photoSelectResult = null');
72          return;
73        }
74        this.uris = photoSelectResult.photoUris;
75
76        if (this.writeSrcToDistributedFile(this.uris)) {
77          Logger.info(TAG, 'copy file success');
78          // 成功写入图片后将标志设为true
79          AppStorage.set('isSelectImg', true);
80          this.isSelectImg = true;
81          Logger.info(TAG, "AppStorage.get<boolean>('isSelectImg') :" + AppStorage.get<boolean>('isSelectImg'));
82        } else {
83          Logger.error(TAG, 'copy file failed');
84        }
85
86        // 获取图库中清晰图片PixelMap
87        // 1.通过uri打开文件得到fd
88        let file = fs.openSync(this.uris[0], fs.OpenMode.READ_ONLY);
89        Logger.info(TAG, 'file.fd:' + file.fd);
90        // 2.通过imageSourceApi来创建pixelMap并直接显示
91        let imageSourceApi = image.createImageSource(file.fd);
92        if (imageSourceApi) {
93          imageSourceApi.createPixelMap().then((pixelMap) => {
94            this.image1 = pixelMap;
95            this.imgIsVisible1 = false;
96          });
97        } else {
98          Logger.info(TAG, 'imageSourceApi is undefined');
99        }
100      })
101    } catch (error) {
102      Logger.error(TAG, 'photoPicker failed with error: ' + JSON.stringify(error));
103    }
104  }
105
106  writeSrcToDistributedFile(uris: string[]): boolean {
107    if (!uris.length) {
108      Logger.error(TAG, 'uri length is empty');
109      return false;
110    }
111    Logger.info(TAG, 'uri length = ' + uris.length);
112    // 选中后先删除之前的文件
113    try {
114      let res = fs.accessSync(filePath);
115      if (res) {
116        fs.unlink(filePath);
117        Logger.info(TAG, ' delete file successfully');
118      } else {
119        Logger.info(TAG, 'delete file failed');
120      }
121      // 重新写文件
122      let srcFile = fs.openSync(uris[0], fs.OpenMode.READ_ONLY);
123      let dstFile = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
124      Logger.info(TAG, 'open srcFile dstFile success!');
125      const bufSize = 4096;
126      let readSize = 0;
127      let buf = new ArrayBuffer(bufSize);
128      let readLen = fs.readSync(srcFile.fd as number, buf, { offset: readSize });
129      while (readLen > 0) {
130        readSize += readLen;
131        fs.writeSync(dstFile.fd as number, buf, { length: readLen });
132        readLen = fs.readSync(srcFile.fd as number, buf, { offset: readSize });
133      }
134      Logger.info(TAG, 'copy file success size: ' + readSize);
135      fs.close(srcFile);
136      fs.close(dstFile);
137      return true;
138    } catch (error) {
139      Logger.error(TAG, 'open file fail with err: ' + JSON.stringify(error));
140      return false;
141    }
142  }
143
144  readFromDistributedFile(): void {
145    Logger.info(TAG, 'readFromDistributedFile: filePath: ' + filePath);
146    try {
147      Logger.info(TAG, 'readFromDistributedFile try to read');
148      // 查看并打开分布式目录下的文件
149      if (fs.accessSync(filePath)) {
150        Logger.info(TAG, filePath + ' exists');
151      } else {
152        Logger.error(TAG, filePath + 'not exists');
153        return;
154      }
155      // 通过imageSourceApi来创建pixelMap 并负责流转后展示
156      let imageSourceApi = image.createImageSource(filePath);
157      imageSourceApi.createPixelMap().then((pixelMap) => {
158        this.image1 = pixelMap;
159        this.imgIsVisible1 = false;
160      });
161      Logger.info(TAG, 'readFromDistributedFile is ready');
162    } catch (error) {
163      Logger.error(TAG, 'readFromDistributedFile failed with error :' + JSON.stringify(error));
164    }
165  }
166
167  choosePictureFileForImage2(): void {
168    try {
169      let photoSelectOptions = new picker.PhotoSelectOptions();
170      photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
171      photoSelectOptions.maxSelectNumber = 1;
172      let photoPicker = new picker.PhotoViewPicker();
173      photoPicker.select(photoSelectOptions).then((photoSelectResult) => {
174        if (!photoSelectResult) {
175          Logger.error(TAG, 'choosePicture2 photoSelectResult = null');
176          return;
177        }
178        this.uris2 = photoSelectResult.photoUris;
179
180        if (this.writeDistributedAsset()) {
181          Logger.info(TAG, "choosePicture2 success");
182        } else {
183          Logger.error(TAG, 'choosePicture2 failed');
184        }
185
186        // 获取图库中清晰图片PixelMap
187        // 1.通过uri打开文件得到fd
188        let file = fs.openSync(this.uris2[0], fs.OpenMode.READ_ONLY);
189        // 2.通过imageSourceApi来创建pixelMap并直接显示
190        let imageSourceApi = image.createImageSource(file.fd);
191        if (imageSourceApi) {
192          imageSourceApi.createPixelMap().then((pixelMap) => {
193            this.image2 = pixelMap;
194            this.imgIsVisible2 = false;
195          });
196          AppStorage.setOrCreate<string>('image2Path', CommonConstants.DISTRIBUTED_ASSET_SAVE_PATH);
197        } else {
198          Logger.info(TAG, 'choosePicture2 imageSourceApi is undefined');
199        }
200      })
201    } catch (error) {
202      Logger.error(TAG, 'choosePicture2 photoPicker failed with error: ' + JSON.stringify(error));
203    }
204  }
205
206  writeDistributedAsset(): boolean {
207    Logger.info(TAG, 'writeDistributedAsset in');
208    // 删除目录
209    try {
210      fs.rmdirSync(CommonConstants.DISTRIBUTED_ASSET_DIR);
211      Logger.info(TAG, 'remove dir successful');
212    } catch (error) {
213      Logger.info(TAG, `remove dir failed, cause: ${JSON.stringify(error)}`);
214    }
215    try {
216      fs.mkdirSync(CommonConstants.DISTRIBUTED_ASSET_DIR, true);
217      let srcFile = fs.openSync(this.uris2[0], fs.OpenMode.READ_ONLY);
218      let dstFile = fs.openSync(CommonConstants.DISTRIBUTED_ASSET_SAVE_PATH, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
219      Logger.info(TAG, 'writeDistributedAsset open srcFile dstFile success!');
220      const bufSize = 4096;
221      let readSize = 0;
222      let buf = new ArrayBuffer(bufSize);
223      let readLen = fs.readSync(srcFile.fd as number, buf, { offset: readSize });
224      while (readLen > 0) {
225        readSize += readLen;
226        fs.writeSync(dstFile.fd as number, buf, { length: readLen });
227        readLen = fs.readSync(srcFile.fd as number, buf, { offset: readSize });
228      }
229      Logger.info(TAG, 'copy file success size: ' + readSize);
230      fs.close(srcFile);
231      fs.close(dstFile);
232      return true;
233    } catch (error) {
234      Logger.error(TAG, `writeDistributedAsset error, cause: ${JSON.stringify(error)}`);
235    }
236    return false;
237  }
238
239  readDistributedAsset(): void {
240    Logger.info(TAG, 'readDistributedAsset in');
241    try {
242      let image2Path = AppStorage.get<string>('image2Path');
243      if (image2Path == undefined || image2Path == '') {
244        Logger.info(TAG, `image2Path error, cause: $JSON.stringify(image2Path)`);
245        return;
246      }
247      if (fs.accessSync(image2Path)) {
248        Logger.info(TAG, 'open distributed asset successfully');
249      } else {
250        Logger.error(TAG, 'distributed asset does not exists');
251        return;
252      }
253      let imageSource = image.createImageSource(image2Path);
254      imageSource.createPixelMap().then((pixelMap) => {
255        Logger.info(TAG, 'createPixelMap successfully')
256        this.image2 = pixelMap;
257        this.imgIsVisible2 = false;
258      })
259      Logger.info(TAG, 'readDistributedAsset successfully');
260    } catch (error) {
261      Logger.error(TAG, `readDistributedAsset error, cause: ${JSON.stringify(error)}`);
262    }
263  }
264
265  aboutToAppear() {
266    Logger.info(TAG, 'aboutToAppear in');
267    LooperUtil.on(CommonConstants.EVENT_DATA_RESTORE, () => {
268      this.readDistributedAsset();
269    });
270    if (this.isContinuation) {
271      if (this.isSelectImg) {
272        this.readFromDistributedFile();
273      }
274    }
275  }
276
277  aboutToDisappear(): void {
278    Logger.info(TAG, 'aboutToDisappear in');
279    LooperUtil.off(CommonConstants.EVENT_DATA_RESTORE);
280    AppStorage.set<string>('image2Path', '');
281    this.isSelectImg = false;
282    this.imgIsVisible1 = true;
283    this.imgIsVisible2 = true;
284  }
285
286  build() {
287    Row() {
288      Column() {
289        Column() {
290
291          // 顶部导航
292          Flex({ direction: FlexDirection.Row }) {
293            Row() {
294              Image($r('app.media.ic_back'))
295                .width(24)
296                .height(24)
297                .margin({ right: 16 })
298                .id('back_arrow_notes')
299
300            }
301            .width(30)
302            .height(30)
303            .onClick(() => {
304              router.back()
305            })
306
307            Text(CommonConstants.NOTES_TITLE)
308              .fontSize(20)
309              .fontWeight(500)
310              .margin({ top: 5, left: 16 })
311
312          }
313          .margin({ top: 36, left: 24, bottom: 14 })
314          .width(360)
315
316          Column() {
317
318            TextInput({ text: this.inputText,
319              placeholder: CommonConstants.PLEASE_INPUT_NOTE_TITLE
320            })
321              .fontWeight(500)
322              .fontSize(30)
323              .textAlign(TextAlign.JUSTIFY)
324              .align(Alignment.Center)
325              .height(51)
326              .onChange((value: string) => {
327                this.inputText = value;
328                AppStorage.set('inputText', value);
329                Logger.info(TAG, 'this.inputText: ' + this.inputText);
330              })
331              .type(InputType.Normal)
332              .backgroundColor(Color.Transparent)
333              .margin({ left: -14 })
334              .restoreId(2)
335              .id('textInput')
336
337
338            Text(CommonConstants.NOTES_TIME)
339              .fontWeight(400)
340              .fontSize(14)
341              .textAlign(TextAlign.JUSTIFY)
342              .fontColor('#182431')
343              .lineHeight(19)
344
345            TextArea({
346              text: this.inputTextArea,
347              placeholder: CommonConstants.PLEASE_INPUT_NOTE_CONTENT,
348              controller: this.controller
349            })
350              .placeholderFont({ size: 16, weight: 400 })
351              .placeholderColor('#182431')
352              .width('100%')
353              .height(126)
354              .margin({ top: 16 })
355              .fontSize(16)
356              .fontColor('#182431')
357              .backgroundColor('#FFFFFF')
358              .onChange((value: string) => {
359                this.inputTextArea = value;
360                AppStorage.set('inputTextArea', value);
361              })
362              .restoreId(3)
363              .id('textArea')
364
365
366            // 分布式文件: 迁移图片1
367            Row() {
368              // 初始占位小图
369              Image(this.imgArray[0])
370                .width(48)
371                .height(48)
372                .margin({ left: 144 })
373                .visibility(this.imgIsVisible1 ? Visibility.Visible : Visibility.None)
374              //大图
375              Image(this.image1)
376                .width('100%')
377                .height('100%')
378                .borderRadius(24)
379                .syncLoad(true)
380                .onComplete((msg) => {
381                  Logger.info(TAG, 'load image success 01');
382                })// 图片获取失败打印结果
383                .onError(() => {
384                  Logger.info(TAG, 'load image fail 01');
385                })
386                .visibility(this.imgIsVisible1 ? Visibility.None : Visibility.Visible)
387            }
388            .width('100%')
389            .height(154)
390            .backgroundColor('#FFFFFF')
391            .borderRadius(24)
392            .margin({ top: 12 })
393
394            Text($r('app.string.PICTURE_ONE'))
395              .fontSize(12)
396              .fontColor('#182431')
397              .height(16)
398              .fontWeight(500)
399              .margin({ top: 8, left: 152 })
400            // 分布式对象携带附件: 迁移图片2
401            Row() {
402              // 初始站位小图
403              Image(this.imgArray[0])
404                .width(48)
405                .height(48)
406                .margin({ left: 144 })
407                .visibility(this.imgIsVisible2 ? Visibility.Visible : Visibility.None)
408              // 大图
409              Image(this.image2 as PixelMap)
410                .width('100%')
411                .height('100%')
412                .borderRadius(24)
413                .syncLoad(true)
414                .onComplete((msg) => {
415                  Logger.info(TAG, 'load image success 03');
416                })// 图片获取失败打印结果
417                .onError(() => {
418                  Logger.info(TAG, 'load image fail 03')
419                })
420                .visibility(this.imgIsVisible2 ? Visibility.None : Visibility.Visible)
421            }
422            .width('100%')
423            .height(154)
424            .backgroundColor('#FFFFFF')
425            .borderRadius(24)
426            .margin({ top: 12 })
427
428            Text($r('app.string.PICTURE_TWO'))
429              .fontSize(12)
430              .fontColor('#182431')
431              .height(16)
432              .fontWeight(500)
433              .margin({ top: 8, left: 152, bottom: 32 })
434
435            Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
436              Button($r('app.string.pick_photo_one'), { type: ButtonType.Capsule, stateEffect: true })
437                .backgroundColor('rgba(24,36,49,0.05)')
438                .width(150)
439                .height(40)
440                .fontColor('#007DFF')
441                .margin({ right: 12 })
442                .onClick(() => {
443                  this.choosePictureFile();
444                })
445                .id('button_select_picture_One')
446
447
448              Button($r('app.string.pick_photo_two'), { type: ButtonType.Capsule, stateEffect: true })
449                .backgroundColor('rgba(24,36,49,0.05)')
450                .width(150)
451                .height(40)
452                .fontColor('#007DFF')
453                .onClick(() => {
454                  this.choosePictureFileForImage2();
455                })
456                .id('button_select_picture_two')
457
458            }
459          }
460          .width(336)
461          .alignItems(HorizontalAlign.Start)
462        }
463        .width(360)
464        .alignItems(HorizontalAlign.Center)
465      }
466      .width('100%')
467      .height('100%')
468    }
469    .width('100%')
470    .height('100%')
471    .alignItems(VerticalAlign.Top)
472    .backgroundColor('#f1f3f5')
473  }
474}