• 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 DateUtil from '@ohos/utils/src/main/ets/default/baseUtil/DateUtil';
17import RdbStoreUtil from '@ohos/utils/src/main/ets/default/baseUtil/RdbStoreUtil';
18import FolderData from '@ohos/utils/src/main/ets/default/model/databaseModel/FolderData';
19import NoteData from '@ohos/utils/src/main/ets/default/model/databaseModel/NoteData';
20import {
21  TableName,
22  NoteTableColumn,
23  SysDefFolderUuid,
24  Favorite,
25  Delete,
26  FolderType
27} from '@ohos/utils/src/main/ets/default/model/databaseModel/EnumData';
28import StyleConstants from '@ohos/utils/src/main/ets/default/constants/StyleConstants';
29import { EditContentDialog, DeleteDialog, EditTitleDialog } from './CusDialogComp';
30import FolderUtil from '@ohos/utils/src/main/ets/default/baseUtil/FolderUtil';
31import NoteUtil from '@ohos/utils/src/main/ets/default/baseUtil/NoteUtil';
32import { promptAction } from '@kit.ArkUI';
33import util from '@ohos.util';
34import { LogUtil } from '@ohos/utils/src/main/ets/default/baseUtil/LogUtil';
35import OperationUtils from '@ohos/utils/src/main/ets/default/baseUtil/OperationUtils';
36import mediaquery from '@ohos.mediaquery';
37import inputMethod from '@ohos.inputMethod';
38import { folderTextMap } from '@ohos/utils/src/main/ets/default/model/NoteBaseData';
39import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
40import webview from '@ohos.web.webview';
41import common from '@ohos.app.ability.common';
42import { BusinessError } from '@ohos.base';
43import resourceManager from '@ohos.resourceManager';
44
45const TAG = 'NoteContentComp';
46
47let timeId: number = 0;
48let noteContext = AppStorage.Get<common.UIAbilityContext>('noteContext')!;
49
50// Note content component
51let inSetValue: string = AppStorage.Link('inSetValue');
52
53interface NoteContentType {
54  callbackhtml: (html: string) => void;
55  callbackImagePath: (imgName: string) => void;
56  callbackhtmlSave: (html: string) => void;
57  callbackScheduledSave: (html: string) => void;
58  callbackPasteImage: (html: string) => void;
59  callbackGetSize: (fontSize: number) => void;
60}
61
62@Component
63export struct NoteContentComp {
64  @Consume('SelectedNoteData') selectedNoteData: NoteData;
65  @StorageLink('AllNoteArray') AllNoteArray: NoteData[] = AppStorage.Link('AllNoteArray');
66  @Consume('SelectedFolderData') selectedFolderData: FolderData;
67  @Consume('RefreshFlag') refreshFlag: number;
68  @Consume('EditModel') editModel: boolean;
69  @Consume('SectionStatus') sectionStatus: number;
70  @Consume('LastSectionStatus') lastSectionStatus: number;
71  @Consume('Issave') issave: number;
72  @Consume('Search') search: boolean;
73  @StorageLink('dpi') dpi: number = 240;
74  controllerShow: webview.WebviewController = new webview.WebviewController();
75  private editContentFlag = false;
76  @State uri1: string = "";
77  private context = getContext(this);
78  @StorageLink('ScrollTopPercent') scrollTopPercent: number = 0.0;
79  @StorageLink('isUpdate') isUpdate: boolean = false;
80  @StorageLink('refreshCurrentNote') @Watch('isDataChange') refreshCurrentNote: boolean = false;
81  @Consume('AsideWidth') asideWidth: number;
82
83  isDataChange() {
84    if (!this.refreshCurrentNote) {
85      return;
86    }
87    try {
88      this.controllerShow.runJavaScript("RICH_EDITOR.setHtml('" + this.selectedNoteData.content_text + "')");
89      LogUtil.info(TAG, `runJavaScript setHtml success.`);
90    } catch (error) {
91      LogUtil.error(TAG, `runJavaScript setHtml failed.code:${JSON.stringify(error.code)},
92        message:${JSON.stringify(error.message)}`);
93    }
94    this.refreshCurrentNote = false;
95  }
96
97  storeScrollTop(scrollTop: number) {
98    if (scrollTop < 0) {
99      return;
100    }
101    AppStorage.SetOrCreate<number>('ScrollTopPercent', scrollTop / this.controllerShow.getPageHeight());
102  }
103
104  restoreScrollTop() {
105    try {
106      if (!AppStorage.Has('remoteScrollTopPercent')) {
107        return;
108      }
109      let scrollTopPercent = AppStorage.Get<number>('remoteScrollTopPercent')!;
110      if (scrollTopPercent < 0) {
111        return;
112      }
113      this.controllerShow.runJavaScript(
114        'document.documentElement.scrollTop = ' + this.controllerShow.getPageHeight() * scrollTopPercent
115      )
116    } catch (error) {
117      LogUtil.error(TAG, `restoreScrollTop failed.code:${JSON.stringify(error.code)},
118      message:${JSON.stringify(error.message)}`);
119    }
120  }
121
122  restoreFocus() {
123    if (!AppStorage.Has('isRemoteFocusOnSearch')) {
124      return;
125    }
126    let isRemoteFocusOnSearch = AppStorage.Get<boolean>('isRemoteFocusOnSearch');
127    if (isRemoteFocusOnSearch) {
128      focusControl.requestFocus('searchInput');
129    }
130    AppStorage.Delete('isRemoteFocusOnSearch');
131  }
132
133  noteContent: NoteContentType = {
134    callbackhtml: (html) => {
135      try {
136        LogUtil.info(TAG, 'note uuid is:' + this.selectedNoteData.uuid);
137        this.selectedNoteData.content_text = NoteUtil.contrastInitType(this.selectedNoteData.content_text);
138        if (this.selectedNoteData.content_text === html) {
139          return;
140        }
141        ;
142        this.selectedNoteData.content_text = html;
143        this.selectedNoteData.modified_time = new Date().getTime();
144        let predicatesNote = RdbStoreUtil.getRdbPredicates(TableName.NoteTable);
145        predicatesNote.equalTo(NoteTableColumn.Uuid, this.selectedNoteData.uuid);
146        RdbStoreUtil.update(this.selectedNoteData.toNoteObject(), predicatesNote, null);
147        LogUtil.info(TAG, 'update note success:' + this.selectedNoteData.uuid);
148        // save continue data
149        let continueNote: string = JSON.stringify(this.selectedNoteData.toNoteObject());
150        AppStorage.SetOrCreate<string>('ContinueNote', continueNote);
151        LogUtil.info(TAG, 'callbackhtml, set continue note success');
152        return 'AceString';
153      } catch (error) {
154        LogUtil.error(TAG, 'callbackhtml error: ' + JSON.stringify(error));
155        return 'AceString';
156      }
157    },
158    callbackImagePath: (imgName) => {
159      // updata note image
160      LogUtil.info(TAG, 'note imgName is:' + imgName);
161      this.selectedNoteData.content_img = imgName;
162    },
163
164    callbackhtmlSave: (html) => {
165      try {
166        LogUtil.info(TAG, 'note uuid is:' + this.selectedNoteData.uuid);
167        this.selectedNoteData.content_text = html;
168        this.selectedNoteData.modified_time = new Date().getTime();
169        let predicatesNote = RdbStoreUtil.getRdbPredicates(TableName.NoteTable);
170        predicatesNote.equalTo(NoteTableColumn.Uuid, this.selectedNoteData.uuid);
171        RdbStoreUtil.update(this.selectedNoteData.toNoteObject(), predicatesNote, null);
172        LogUtil.info(TAG, 'update note success:' + this.selectedNoteData.uuid);
173        this.sectionStatus = this.lastSectionStatus;
174        this.sectionStatus = mediaquery.matchMediaSync('(width < 2000)').matches ? 2 : 3;
175        // save continue data
176        let continueNote: string = JSON.stringify(this.selectedNoteData.toNoteObject());
177        AppStorage.SetOrCreate<string>('ContinueNote', continueNote);
178        AppStorage.SetOrCreate<number>('ContinueSection', this.sectionStatus);
179        LogUtil.info(TAG, 'callbackhtmlSave, set continue note and section success');
180        return 'AceString';
181      } catch (error) {
182        LogUtil.error(TAG, 'callbackhtmlSave error: ' + JSON.stringify(error));
183        return 'AceString';
184      }
185    },
186
187    callbackScheduledSave: (html) => {
188      try {
189        LogUtil.info(TAG, 'callbackScheduledSave');
190        if (this.selectedNoteData.content_text == html) {
191          LogUtil.info(TAG, 'callbackScheduledSave the same value return');
192          return;
193        }
194        this.selectedNoteData.content_text = html;
195        this.selectedNoteData.modified_time = new Date().getTime();
196        let predicatesNote = RdbStoreUtil.getRdbPredicates(TableName.NoteTable);
197        predicatesNote.equalTo(NoteTableColumn.Uuid, this.selectedNoteData.uuid);
198        RdbStoreUtil.update(this.selectedNoteData.toNoteObject(), predicatesNote, null);
199        LogUtil.info(TAG, 'callbackScheduledSave, update note success:' + this.selectedNoteData.uuid);
200        // save continue data
201        let continueNote: string = JSON.stringify(this.selectedNoteData.toNoteObject());
202        AppStorage.SetOrCreate<string>('ContinueNote', continueNote);
203        LogUtil.info(TAG, 'callbackScheduledSave, set continue note success');
204      } catch (error) {
205        LogUtil.error(TAG, 'callbackScheduledSave error: ' + JSON.stringify(error));
206      }
207    },
208
209    callbackPasteImage: (html) => {
210      try {
211        if (html) {
212          LogUtil.info(TAG, 'paste info' + html);
213          let realHtml = "";
214          let base64regex: RegExp = new RegExp('/^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/');
215          if (html && html.indexOf('base64') > 0) {
216            LogUtil.info(TAG, ' getSrcFromHtml, src[1] : ' + html);
217            let imgData = html.split(',')[1];
218            let imgType = 'png';
219            if (html.indexOf('jpeg') > 0) {
220              imgType = 'jpg';
221            } else if (html.indexOf('gif') > 0) {
222              imgType = 'gif';
223            }
224            let filePath = "";
225            if (base64regex.test(imgData)) {
226              let base64 = new util.Base64();
227              let decodeArr = base64.decodeSync(imgData);
228              filePath = OperationUtils.saveImageData(decodeArr, imgType);
229            } else {
230              filePath = OperationUtils.saveImage(imgData, imgType);
231            }
232            realHtml = 'file://' + filePath;
233          }
234          LogUtil.info(TAG, 'paste info11-' + realHtml);
235          this.controllerShow.runJavaScript("javascript:RICH_EDITOR.insertImageHtml('" + realHtml + "')");
236          LogUtil.info(TAG, 'paste info11--' + realHtml);
237        } else {
238          LogUtil.info(TAG, 'paste info22225');
239        }
240      } catch (error) {
241        LogUtil.error(TAG, `callbackPasteImage failed.code:${JSON.stringify(error.code)},
242        message:${JSON.stringify(error.message)}`);
243      }
244    },
245    callbackGetSize: (fontSize) => {
246      if (fontSize === 16) {
247        this.selectedNoteData.slider_value = 0;
248      } else if (fontSize === 18) {
249        this.selectedNoteData.slider_value = 4;
250      } else if (fontSize === 24) {
251        this.selectedNoteData.slider_value = 8;
252      } else if (fontSize === 32) {
253        this.selectedNoteData.slider_value = 12;
254      } else if (fontSize === 48) {
255        this.selectedNoteData.slider_value = 16;
256      }
257    }
258  }
259
260  build() {
261    Stack({ alignContent: Alignment.Bottom }) {
262      Flex({
263        direction: FlexDirection.Column,
264        wrap: FlexWrap.NoWrap,
265        alignItems: ItemAlign.Start,
266        alignContent: FlexAlign.SpaceAround
267      }) {
268        Column() {
269          ToolBarComp({ controllerShow: this.controllerShow })
270        }
271        .margin({ left: 24, right: 24 })
272
273        Column() {
274          NoteContentOverViewComp({ controllerShow: this.controllerShow })
275          Text(this.refreshFlag.toString()).visibility(Visibility.None)
276          Text(this.AllNoteArray.length.toString()).visibility(Visibility.None) // 用于强制刷新使用
277
278          Web({ src: $rawfile('editor.html'), controller: this.controllerShow })
279            .javaScriptAccess(true)
280            .javaScriptProxy({
281              object: this.noteContent,
282              name: 'callBackToApp', // html-->  name.method
283              methodList: ['callbackhtml', 'callbackhtmlSave', 'callbackScheduledSave', 'callbackGetSize',
284                'callbackPasteImage', 'callbackImagePath'],
285              controller: this.controllerShow
286            })
287            .enabled(this.sectionStatus !== 1 ? false : true)
288            .onPageEnd((e) => {
289              try {
290                if (this.dpi <= 240) {
291                  this.controllerShow.runJavaScript('changeSizeToRk()');
292                } else if (this.dpi <= 320 && this.dpi > 240) {
293                  this.controllerShow.runJavaScript('changeSizeToPhone()');
294                } else {
295                  this.controllerShow.runJavaScript('changeSizeToTablet()');
296                }
297                if (AppStorage.Get('breakPoint') !== 'sm') {
298                  this.controllerShow.runJavaScript('hiddenButton()');
299                }
300                LogUtil.info(TAG, 'finish loadurl');
301                if (this.selectedNoteData) {
302                  let self = this;
303                  this.controllerShow.runJavaScript(
304                    "RICH_EDITOR.setHtml('" + this.selectedNoteData.content_text + "')",
305                    () => {
306                      // wait for the image in the note to load
307                      setTimeout(() => {
308                        self.restoreScrollTop();
309                        self.restoreFocus();
310                      }, 100)
311                    }
312                  );
313                }
314                // 初次加载为为小屏预览模式
315                if (this.sectionStatus != 1) {
316                  this.controllerShow.runJavaScript('RICH_EDITOR.setInputEnabled(false)');
317                }
318              } catch (error) {
319                LogUtil.info(TAG,
320                  `runJavaScript onPageEnd error. code:${JSON.stringify(error.code)},message:${error.message}`);
321              }
322            })
323            .imageAccess(true)
324            .onlineImageAccess(true)
325            .fileAccess(true)
326            .domStorageAccess(true)
327            .zoomAccess(false)
328            .height('88%')
329            .width('100%')
330            .onScroll((event) => {
331              this.storeScrollTop(event.yOffset);
332            })
333        }
334        .margin({ left: 24, right: 24 })
335        //        .width(StyleConstants.PERCENTAGE_100)
336        .enabled(this.selectedNoteData && this.selectedNoteData.is_deleted == Delete.Yes ? false : true)
337        .onClick(() => {
338          try {
339            this.issave = 0;
340            LogUtil.info(TAG, 'editModel : ' + this.editModel + ', sectionStatus : ' + this.sectionStatus);
341            let isContinue = AppStorage.Get<boolean>('IsContinue');
342            LogUtil.info(TAG, 'isContinue : ' + isContinue);
343            // 点击第三屏进入全屏编辑模式
344            if (this.sectionStatus != 1 || isContinue) {
345              this.asideWidth = 0;
346              this.lastSectionStatus = this.sectionStatus;
347              this.sectionStatus = 1;
348              this.controllerShow.runJavaScript('RICH_EDITOR.setInputEnabled(true)');
349              // 添加定时器:3s自动保存
350              if (timeId) {
351                clearInterval(timeId);
352              }
353              timeId = setInterval(() => {
354                this.controllerShow.runJavaScript('scheduledSaveContent()');
355              }, 3000)
356              LogUtil.info(TAG, 'setInterval timeId : ' + timeId);
357              // save continue data
358              AppStorage.SetOrCreate<number>('ContinueSection', this.sectionStatus);
359              LogUtil.info(TAG, 'set continue section success');
360              this.editModel = !this.editModel;
361              AppStorage.SetOrCreate<boolean>('IsContinue', false);
362            }
363          } catch (error) {
364            LogUtil.error(TAG, `Column failed.code:${JSON.stringify(error.code)},
365            message:${JSON.stringify(error.message)}`);
366          }
367        })
368      }
369      .id(this.isUpdate + '')
370      .height(StyleConstants.PERCENTAGE_100)
371      .visibility(FolderUtil.getNoteCount(AppStorage.Get('AllNoteArray'), this.selectedFolderData.uuid) == 0 ?
372      Visibility.Hidden : Visibility.Visible)
373
374      Column() {
375      }
376      .height('100%')
377      .width('100%')
378      .backgroundColor('#18181A')
379      .opacity(0.1)
380      .visibility(this.search ? Visibility.Visible : Visibility.Hidden)
381    }
382    .height(StyleConstants.PERCENTAGE_100)
383    .width(StyleConstants.PERCENTAGE_100)
384  }
385
386  aboutToAppear(): void {
387    LogUtil.info(TAG, 'aboutToAppear')
388  }
389
390  aboutToDisappear(): void {
391    clearInterval(timeId)
392    LogUtil.info(TAG, 'aboutToDisappear')
393  }
394}
395
396@Component
397export struct NoteContentOverViewComp {
398  @Consume('SelectedNoteData') selectedNoteData: NoteData;
399  @StorageLink('AllFolderArray') @Watch('getArray') AllFolderArray: FolderData[] = [];
400  @StorageLink('CheckedNoteArray') CheckedNoteArray: NoteData[] = [];
401  @StorageLink('AllNoteArray') AllNoteArray: NoteData[] = AppStorage.Link('AllNoteArray');
402  @Consume('SelectedFolderData') selectedFolderData: FolderData;
403  @Consume('EditModel') editModel: boolean;
404  @Consume('SectionStatus') sectionStatus: number;
405  @Consume('RefreshFlag') refreshFlag: number;
406  @StorageLink('isUpdate') isUpdate: boolean = false;
407  NoteDataMoveArray: FolderData[] = [];
408  controllerShow: webview.WebviewController = new webview.WebviewController();
409  editTitleDialogCtl: CustomDialogController | null = new CustomDialogController({
410    builder: EditContentDialog({
411      confirm: (newTitle: string) => {
412        this.confirm(newTitle);
413      }
414    }),
415    alignment: DialogAlignment.Center,
416    autoCancel: false,
417    customStyle: true,
418  })
419
420  getArray() {
421    this.NoteDataMoveArray = this.AllFolderArray.slice(2, this.AllFolderArray.length);
422    if (this.AllFolderArray[1] === undefined || this.AllFolderArray[1] === null) {
423      LogUtil.info(TAG, 'this AllFolderArray[1] undefined');
424      return;
425    }
426    this.NoteDataMoveArray.push(this.AllFolderArray[1]);
427  }
428
429  aboutToAppear() {
430    this.NoteDataMoveArray = this.AllFolderArray.slice(2, this.AllFolderArray.length);
431    if (this.AllFolderArray[1] === undefined || this.AllFolderArray[1] === null) {
432      LogUtil.info(TAG, 'this AllFolderArray[1] undefined');
433      return;
434    }
435    this.NoteDataMoveArray.push(this.AllFolderArray[1]);
436  }
437
438  aboutToDisappear() {
439    this.editTitleDialogCtl = null;
440  }
441
442  confirm(newTitle: string) {
443    try {
444      this.selectedNoteData.title = newTitle;
445      this.selectedNoteData.modified_time = new Date().getTime();
446      let predicatesNote = RdbStoreUtil.getRdbPredicates(TableName.NoteTable);
447      predicatesNote.equalTo(NoteTableColumn.Uuid, this.selectedNoteData.uuid);
448      RdbStoreUtil.update(this.selectedNoteData.toNoteObject(), predicatesNote, null);
449      NoteUtil.refreshAll();
450    } catch (error) {
451      LogUtil.error(TAG, 'confirm error: ' + JSON.stringify(error));
452    }
453  }
454
455  @Builder
456  MenuBuilder() {
457    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
458      List() {
459        if (this.NoteDataMoveArray !== undefined && this.NoteDataMoveArray !== null &&
460          this.NoteDataMoveArray.length > 0) {
461          ForEach(this.NoteDataMoveArray, (item: FolderData) => {
462            ListItem() {
463              NoteDataMoveItemCompTablet({ folderItem: item, uuid: this.selectedNoteData.folder_uuid })
464            }
465            .onClick(() => {
466              try {
467                this.selectedNoteData.folder_uuid = item.uuid;
468                let predicatesNote = RdbStoreUtil.getRdbPredicates(TableName.NoteTable);
469                predicatesNote.equalTo(NoteTableColumn.Uuid, this.selectedNoteData.uuid);
470                RdbStoreUtil.update(this.selectedNoteData.toNoteObject(), predicatesNote, null);
471                if (this.sectionStatus != 1) {
472                  this.selectedNoteData = NoteUtil.getFirstNoteData(this.AllNoteArray, this.selectedFolderData.uuid)!;
473                  this.controllerShow.runJavaScript(
474                    "RICH_EDITOR.setHtml('" + this.selectedNoteData.content_text + "')"
475                  )
476                  this.refreshFlag = (this.refreshFlag == 0 ? 1 : 0);
477                } else {
478                  this.selectedFolderData = FolderUtil.getFolderData(AppStorage.Get('AllFolderArray')!, item.uuid);
479                }
480                // save continue data
481                let continueNote: string = JSON.stringify(this.selectedNoteData.toNoteObject());
482                AppStorage.SetOrCreate<string>('ContinueNote', continueNote);
483                LogUtil.info(TAG, 'NoteContentOverViewComp, MenuBuilder, set continue note success');
484                NoteUtil.refreshAll();
485              } catch (error) {
486                LogUtil.error(TAG, 'ListItem click error: ' + JSON.stringify(error));
487              }
488            })
489          }, (noteItem: NoteData) => noteItem.uuid)
490        }
491      }.listDirection(Axis.Vertical)
492      .edgeEffect(EdgeEffect.Spring)
493      .height(this.AllFolderArray.length > 12 ? 504 : (this.AllFolderArray.length - 3) * 56)
494    }
495    .width(148)
496    .backgroundColor($r('app.color.color_fffffB'))
497    .padding({ left: 24, right: 24 })
498  }
499
500  build() {
501    if (this.selectedNoteData) {
502      Flex({
503        direction: FlexDirection.Column,
504        wrap: FlexWrap.NoWrap,
505        justifyContent: FlexAlign.SpaceBetween,
506        alignItems: ItemAlign.Center
507      }) {
508        Row() {
509          Text(this.selectedNoteData.title)
510            .id(this.isUpdate + '')
511            .fontSize(30)
512            .margin({ left: 0, right: 24 })
513            .onClick(() => {
514              clearInterval(timeId);
515              this.editTitleDialogCtl!.open();
516              // save continue data
517              AppStorage.SetOrCreate<number>('ContinueSection', this.sectionStatus);
518              LogUtil.info(TAG, 'NoteContentComp, set continue section success');
519            })
520        }.height(40)
521        .width(StyleConstants.PERCENTAGE_100)
522
523        Row() {
524          Text(DateUtil.formateDateForNoteContent(new Date(this.selectedNoteData.modified_time)))
525            .id(this.isUpdate + '')
526            .fontSize(12)
527            .padding({ top: 4, bottom: 4 })
528            .fontColor($r('app.color.modified_time_font_color'))
529            .margin({ left: 0 })
530          Row() {
531            Text(FolderUtil.getFolderText(FolderUtil.getFolderData(AppStorage.Get('AllFolderArray'),
532              this.selectedNoteData.folder_uuid)) ==
533            folderTextMap.sys_def_myFavorites_uuid ? folderTextMap.sys_def_unClassified_uuid :
534            FolderUtil.getFolderText(FolderUtil.getFolderData(AppStorage.Get('AllFolderArray'),
535              this.selectedNoteData.folder_uuid)))
536              .id(this.isUpdate + '')
537              .fontSize(12)
538              .fontColor($r('app.color.list_modified_time_font_color'))
539              .padding({ top: 1 })
540            Image($r('app.media.triangle'))
541              .width(6)
542              .height(12)
543              .margin({ left: 4 })
544          }
545          .id(this.isUpdate + '')
546          .padding({
547            left: 8,
548            right: 8,
549            top: 4,
550            bottom: 4
551          })
552          .margin({ left: 8 })
553          .borderRadius(16)
554          .backgroundColor(NoteUtil.getNoteBgColor(AppStorage.Get('AllFolderArray')!, this.selectedNoteData.folder_uuid,
555            SysDefFolderUuid.AllNotes, false))
556          .bindMenu(this.MenuBuilder)
557        }.alignItems(VerticalAlign.Top).height(40).width(StyleConstants.PERCENTAGE_100)
558      }
559      .opacity(this.selectedNoteData.is_deleted == Delete.Yes ? 0.4 : 1)
560      .width(StyleConstants.PERCENTAGE_100)
561      .height(80)
562    }
563  }
564}
565
566@Component
567export struct ToolBarComp {
568  @Consume('SelectedNoteData') selectedNoteData: NoteData;
569  @Consume('RefreshFlag') refreshFlag: number;
570  @Consume('SectionStatus') sectionStatus: number;
571  @Consume('LastSectionStatus') lastSectionStatus: number;
572  @Consume('SelectedFolderData') selectedFolderData: FolderData;
573  @Consume('ChooseNote') chooseNote: boolean;
574  @Consume('PortraitModel') portraitModel: boolean;
575  @StorageLink('AllNoteArray') AllNoteArray: NoteData[] = AppStorage.Link('AllNoteArray');
576  @Consume('EditModel') editModel: boolean;
577  @Consume('Issave') issave: number;
578  controllerShow: webview.WebviewController = new webview.WebviewController();
579  private context = getContext(this);
580  noteDataDeleteDialogCtl: CustomDialogController | null = new CustomDialogController({
581    builder: DeleteDialog({
582      onConfirm: () => {
583        this.onDeleteConfirm();
584      }
585    }),
586    alignment: DialogAlignment.Center,
587    autoCancel: false,
588    customStyle: true,
589  });
590  @Consume('AsideWidth') asideWidth: number;
591
592  aboutToDisappear() {
593    this.noteDataDeleteDialogCtl = null;
594    this.editContentDialogCtl = null;
595  }
596
597  onDeleteConfirm() {
598    try {
599      if (this.selectedFolderData.uuid != SysDefFolderUuid.RecentDeletes) {
600        this.selectedNoteData.is_deleted = Delete.Yes;
601        this.selectedNoteData.deleted_time = new Date().getTime();
602        // update note to db
603        let predicatesNote = RdbStoreUtil.getRdbPredicates(TableName.NoteTable);
604        predicatesNote.equalTo(NoteTableColumn.Uuid, this.selectedNoteData.uuid);
605        RdbStoreUtil.update(this.selectedNoteData.toNoteObject(), predicatesNote, null);
606      } else {
607        NoteUtil.removeNoteData(this.AllNoteArray, this.selectedNoteData.uuid);
608        // delete note from db
609        let predicatesNote = RdbStoreUtil.getRdbPredicates(TableName.NoteTable);
610        predicatesNote.equalTo(NoteTableColumn.Uuid, this.selectedNoteData.uuid);
611        RdbStoreUtil.delete(predicatesNote, null);
612      }
613      this.refreshFlag = (this.refreshFlag == 0 ? 1 : 0);
614      this.selectedNoteData = NoteUtil.getFirstNoteData(AppStorage.Get('AllNoteArray')!, this.selectedFolderData.uuid)!;
615      try {
616        this.controllerShow.runJavaScript("RICH_EDITOR.setHtml('" + this.selectedNoteData.content_text! + "')");
617      } catch (error) {
618        LogUtil.info(TAG, `setHtml error. code:${JSON.stringify(error.code)},message:${error.message}`);
619      }
620      this.chooseNote = false;
621      // save continue data
622      let continueNote: string = JSON.stringify(this.selectedNoteData.toNoteObject());
623      AppStorage.SetOrCreate<string>('ContinueNote', continueNote);
624      LogUtil.info(TAG, 'NoteContentOverViewComp, set continue note success');
625      AppStorage.SetOrCreate('isUpdate', true);
626    } catch (error) {
627      LogUtil.error(TAG, 'onDeleteConfirm error: ' + JSON.stringify(error));
628    }
629  }
630
631  editContentDialogCtl: CustomDialogController | null = new CustomDialogController({
632    builder: EditContentDialog({
633      confirm: (newTitle: string) => {
634        this.confirm(newTitle);
635      }
636    }),
637    alignment: DialogAlignment.Bottom,
638    autoCancel: true,
639    customStyle: true,
640  })
641
642  confirm(excuteJs: string) {
643    this.controllerShow.runJavaScript(excuteJs);
644  }
645
646  build() {
647    Flex({
648      direction: FlexDirection.Row,
649      wrap: FlexWrap.NoWrap,
650      justifyContent: FlexAlign.SpaceBetween,
651      alignItems: ItemAlign.Center
652    }) {
653      Image(this.sectionStatus == 1 ? $r('app.media.narrow') : $r('app.media.zoom'))
654        .height(24)
655        .width(24)
656        .onClick(() => {
657          try {
658            if (this.sectionStatus != 1) {
659              this.lastSectionStatus = this.sectionStatus;
660              this.sectionStatus = 1;
661              this.asideWidth = 0;
662              this.controllerShow.runJavaScript('RICH_EDITOR.setInputEnabled(true)');
663            } else {
664              if (this.lastSectionStatus != undefined) {
665                this.asideWidth = 200;
666                // 切换为小屏预览模式
667                this.controllerShow.runJavaScript('RICH_EDITOR.setInputEnabled(false)');
668                this.sectionStatus = this.lastSectionStatus;
669                // 退出全屏时存库
670                LogUtil.info(TAG, 'close note' + this.selectedNoteData.uuid);
671                this.controllerShow.runJavaScript('saveHtmlContent()');
672                //退出键盘
673                inputMethod.getController().stopInputSession();
674                // 清除定时器
675                if (timeId != undefined) {
676                  LogUtil.info(TAG, 'zoom, clearInterval timeId : ' + timeId);
677                  clearInterval(timeId);
678                }
679              } else {
680                this.sectionStatus = 3;
681              }
682            }
683            this.editModel = !this.editModel;
684            // save continue data
685            AppStorage.SetOrCreate<number>('ContinueSection', this.sectionStatus);
686            LogUtil.info(TAG, 'ToolBarComp, set continue section success');
687            NoteUtil.refreshAll();
688          } catch (error) {
689            LogUtil.error(TAG,
690              `Image ${this.sectionStatus == 1 ? 'narrow' : 'zoom'} click failed.code:${JSON.stringify(error.code)},
691            message:${JSON.stringify(error.message)}`);
692          }
693        })
694        .visibility(!this.selectedNoteData ? Visibility.None :
695          this.selectedNoteData.is_deleted == Delete.Yes ? Visibility.None : Visibility.Visible)
696
697      if (this.selectedNoteData) {
698        if (this.selectedNoteData.is_deleted == Delete.Yes) {
699          Row({ space: StyleConstants.SPACE_24 }) {
700            Image($r('app.media.delete'))
701              .height(24)
702              .width(24)
703              .onClick(() => {
704                this.noteDataDeleteDialogCtl!.open();
705              })
706            Image($r('app.media.recover'))
707              .height(24)
708              .width(24)
709              .onClick(() => {
710                try {
711                  this.selectedNoteData.is_deleted = Delete.No;
712                  this.selectedNoteData.deleted_time = 0;
713                  let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
714                  let resource: resourceManager.Resource = {
715                    bundleName: 'com.ohos.note',
716                    moduleName: 'default',
717                    id: $r('app.string.restore').id
718                  };
719                  context.resourceManager.getStringValue(resource, (error: BusinessError, value: string) => {
720                    if (error != null) {
721                      LogUtil.error(TAG, 'error is ' + error);
722                    } else {
723                      promptAction.showToast({ message: value, duration: 2000 });
724                    }
725                  });
726                  this.refreshFlag = (this.refreshFlag == 0 ? 1 : 0);
727                  this.chooseNote = false;
728                  // update note to db
729                  let predicatesNote = RdbStoreUtil.getRdbPredicates(TableName.NoteTable);
730                  predicatesNote.equalTo(NoteTableColumn.Uuid, this.selectedNoteData.uuid);
731                  RdbStoreUtil.update(this.selectedNoteData.toNoteObject(), predicatesNote, null);
732
733                  this.selectedNoteData =
734                    NoteUtil.getFirstNoteData(AppStorage.Get('AllNoteArray')!, this.selectedFolderData.uuid)!;
735                  this.controllerShow.runJavaScript(
736                    "RICH_EDITOR.setHtml('" + this.selectedNoteData!.content_text + "')"
737                  )
738                  // save continue data
739                  let continueNote: string = JSON.stringify(this.selectedNoteData.toNoteObject());
740                  AppStorage.SetOrCreate<string>('ContinueNote', continueNote);
741                  LogUtil.info(TAG, 'recover, set continue note success');
742                  NoteUtil.refreshAll();
743                } catch (error) {
744                  LogUtil.error(TAG,
745                    `recover failed.code:${JSON.stringify(error.code)}, message:${JSON.stringify(error.message)}`);
746                }
747              })
748          }.width(72)
749        } else if (this.editModel == true) {
750          Row({ space: StyleConstants.SPACE_6 }) {
751            Button({ type: ButtonType.Normal, stateEffect: true }) {
752              Image($r('app.media.circle_tick1'))
753                .height(24)
754                .width(24)
755                .onClick(() => {
756                  try {
757                    // 清单
758                    this.controllerShow.runJavaScript('javascript:RICH_EDITOR.setTodo()');
759                    // 退出键盘
760                    inputMethod.getController().stopInputSession();
761                  } catch (error) {
762                    LogUtil.error(TAG, `Image circle_tick1 click failed.code:${JSON.stringify(error.code)},
763                    message:${JSON.stringify(error.message)}`);
764                  }
765                })
766            }.width(42)
767            .height(42)
768            .borderRadius(8)
769            .backgroundColor($r('app.color.color_fffffB'))
770
771            Button({ type: ButtonType.Normal, stateEffect: true }) {
772              Image($r('app.media.styles'))
773                .height(24)
774                .width(24)
775                .onClick(() => {
776                  // 退出键盘
777                  inputMethod.getController().stopInputSession();
778                  this.editContentDialogCtl!.open();
779                })
780            }.width(42)
781            .height(42)
782            .borderRadius(8)
783            .backgroundColor($r('app.color.color_fffffB'))
784
785            Button({ type: ButtonType.Normal, stateEffect: true }) {
786              Image($r('app.media.picture_white'))
787                .height(24)
788                .width(24)
789                .onClick(async () => {
790                  let permissionList: Permissions[] = [
791                    'ohos.permission.READ_MEDIA',
792                    'ohos.permission.WRITE_MEDIA',
793                  ];
794                  let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
795                  let AtManager = abilityAccessCtrl.createAtManager();
796                  await AtManager.requestPermissionsFromUser(context, permissionList).then((data) => {
797                    LogUtil.info(TAG, 'data permissions : ' + data.permissions);
798                    LogUtil.info(TAG, 'data result: ' + data.authResults);
799                    let sum = 0;
800                    for (let i = 0; i < data.authResults.length; i++) {
801                      sum += data.authResults[i];
802                    }
803                    LogUtil.info(TAG, 'request permissions sum: ' + sum);
804                  }).catch((err: BusinessError) => {
805                    LogUtil.warn(TAG, 'failed to requestPermissionsFromUser : ' + err.code);
806                  })
807                  // 退出键盘
808                  inputMethod.getController().stopInputSession();
809                  LogUtil.info(TAG, 'startAbility start');
810                  await noteContext.startAbilityForResult({
811                    parameters: { uri: 'singleselect' },
812                    bundleName: 'com.ohos.photos',
813                    abilityName: 'com.ohos.photos.MainAbility',
814                  })
815                    .then((v: common.AbilityResult) => {
816                      try {
817                        let want = v['want'];
818                        if (want != null && want != undefined) {
819                          let param = want['parameters'];
820                          let imageUri = "";
821                          if (param != null && param != undefined) {
822                            let uri = param['select-item-list'];
823                            imageUri = uri as string;
824                          }
825                          // 拷贝
826                          if (imageUri != null && imageUri != "") {
827                            OperationUtils.copy(imageUri).then((uriPath) => {
828                              let path = 'file://' + uriPath;
829                              LogUtil.info(TAG, 'image uri is:' + path);
830                              this.controllerShow.runJavaScript(
831                                "javascript:RICH_EDITOR.insertImage('" + path + "')"
832                              );
833                              this.issave = 1;
834                              // 保存笔记信息到数据库
835                              this.controllerShow.runJavaScript('getHtmlContent()');
836                            })
837                          }
838                        }
839                        NoteUtil.refreshAll();
840                      } catch (error) {
841                        LogUtil.error(TAG, `startAbilityForResult failed.code:${JSON.stringify(error.code)},
842                        message:${JSON.stringify(error.message)}`);
843                      }
844                    });
845                })
846            }.width(42)
847            .height(42)
848            .borderRadius(8)
849            .backgroundColor($r('app.color.color_fffffB'))
850
851            Button({ type: ButtonType.Normal, stateEffect: true }) {
852              Image($r('app.media.undo'))
853                .height(24)
854                .width(24)
855                .onClick(() => {
856                  try {
857                    // 退出键盘
858                    inputMethod.getController().stopInputSession();
859                    this.controllerShow.runJavaScript('RICH_EDITOR.undo()');
860                  } catch (error) {
861                    LogUtil.error(TAG, `Image undo click failed.code:${JSON.stringify(error.code)},
862                    message:${JSON.stringify(error.message)}`);
863                  }
864                })
865            }.width(42)
866            .height(42)
867            .borderRadius(8)
868            .backgroundColor($r('app.color.color_fffffB'))
869
870            Button({ type: ButtonType.Normal, stateEffect: true }) {
871              Image($r('app.media.todo'))
872                .height(24)
873                .width(24)
874                .onClick(() => {
875                  try {
876                    // 退出键盘
877                    inputMethod.getController().stopInputSession();
878                    this.controllerShow.runJavaScript('RICH_EDITOR.redo()');
879                  } catch (error) {
880                    LogUtil.error(TAG, `Image todo click failed.code:${JSON.stringify(error.code)},
881                    message:${JSON.stringify(error.message)}`);
882                  }
883                })
884            }.width(42)
885            .height(42)
886            .borderRadius(8)
887            .backgroundColor($r('app.color.color_fffffB'))
888
889
890            Button({ type: ButtonType.Normal, stateEffect: true }) {
891              Image($r('app.media.tick_thin'))
892                .height(24)
893                .width(24)
894                .fillColor(this.issave == 0 ? Color.Black : Color.Grey)
895                .onClick(() => {
896                  try {
897                    // 保存笔记信息到数据库
898                    this.controllerShow.runJavaScript('getHtmlContent()');
899                    this.controllerShow.runJavaScript('javascript:RICH_EDITOR.getBlur()');
900                    if (this.selectedNoteData.title == '标题' && this.selectedNoteData.content_text == "") {
901                      LogUtil.info(TAG, 'note is empty,save note failed');
902                    }
903                    this.issave = 1;
904                  } catch (error) {
905                    LogUtil.error(TAG, `Image tick_thin click failed.code:${JSON.stringify(error.code)},
906                    message:${JSON.stringify(error.message)}`);
907                  }
908                })
909            }.width(42)
910            .height(42)
911            .borderRadius(8)
912            .backgroundColor($r('app.color.color_fffffB'))
913          }.width(274)
914        } else {
915          Row({ space: StyleConstants.SPACE_24 }) {
916            Image(this.selectedNoteData.is_favorite == Favorite.Yes ? $r('app.media.favorite') :
917            $r('app.media.favorite_cancel'))
918              .height(24)
919              .width(24)
920              .onClick(() => {
921                try {
922                  this.selectedNoteData.is_favorite =
923                    (this.selectedNoteData.is_favorite == Favorite.Yes ? Favorite.No : Favorite.Yes);
924                  this.refreshFlag = (this.refreshFlag == 0 ? 1 : 0);
925                  // update note to db
926                  let predicatesNote = RdbStoreUtil.getRdbPredicates(TableName.NoteTable);
927                  predicatesNote.equalTo(NoteTableColumn.Uuid, this.selectedNoteData.uuid);
928                  RdbStoreUtil.update(this.selectedNoteData.toNoteObject(), predicatesNote, null);
929                  if (this.selectedFolderData.uuid === SysDefFolderUuid.MyFavorites) {
930                    this.selectedNoteData =
931                      NoteUtil.getFirstNoteData(AppStorage.Get('AllNoteArray')!, SysDefFolderUuid.MyFavorites)!;
932                    try {
933                      this.controllerShow.runJavaScript(
934                        "RICH_EDITOR.setHtml('" + this.selectedNoteData.content_text + "')"
935                      );
936                      LogUtil.info(TAG, `setHtml success`);
937                    } catch (error) {
938                      LogUtil.error(TAG, `setHtml failed.code:${JSON.stringify(error.code)},
939                        message:${JSON.stringify(error.message)}`);
940                    }
941                    // save continue data
942                    let continueNote: string = JSON.stringify(this.selectedNoteData.toNoteObject());
943                    AppStorage.SetOrCreate<string>('ContinueNote', continueNote);
944                    LogUtil.info(TAG, 'ToolBarComp, set continue note success');
945                  }
946                  NoteUtil.refreshAll();
947                } catch (error) {
948                  LogUtil.error(TAG, 'favorite error: ' + JSON.stringify(error));
949                }
950              })
951            Image($r('app.media.delete'))
952              .height(24)
953              .width(24)
954              .onClick(() => {
955                this.noteDataDeleteDialogCtl!.open();
956              })
957          }.width(72)
958        }
959      }
960    }
961    .width(StyleConstants.PERCENTAGE_100)
962    .height(80)
963  }
964}
965
966@Component
967struct NoteDataMoveItemCompTablet {
968  @StorageLink('CheckedNoteArray') CheckedNoteArray: NoteData[] = [];
969  @StorageLink('AllFolderArray') AllFolderArray: FolderData[] = [];
970  @StorageLink('isUpdate') isUpdate: boolean = false;
971  folderItem: FolderData =
972    new FolderData(0, '', new Date().getTime() + '', '', FolderType.CusDef, Delete.No, new Date().getTime(),
973      new Date().getTime());
974  uuid: string = '';
975
976  build() {
977    Flex({ alignItems: ItemAlign.Center, wrap: FlexWrap.NoWrap, justifyContent: FlexAlign.Center }) {
978      Flex({ alignItems: ItemAlign.Center, wrap: FlexWrap.NoWrap }) {
979        Image(FolderUtil.getFolderIcon(this.folderItem.uuid))
980          .id(this.isUpdate + '')
981          .objectFit(ImageFit.Fill)
982          .width(24)
983          .height(24)
984          .flexShrink(0)
985          .fillColor(FolderUtil.getFolderIconColor(this.AllFolderArray, this.folderItem.uuid,
986            this.folderItem.uuid == this.uuid))
987      }
988      .width(24)
989
990      Column() {
991        Flex({ alignItems: ItemAlign.Center, wrap: FlexWrap.NoWrap, justifyContent: FlexAlign.SpaceBetween }) {
992          Text(FolderUtil.getFolderText(this.folderItem))
993            .id(this.isUpdate + '')
994            .padding({ top: 3 })
995            .fontSize(16)
996            .fontColor(FolderUtil.getFolderIconColor(this.AllFolderArray,
997              this.folderItem.uuid == this.uuid ? this.folderItem.uuid : '', this.folderItem.uuid == this.uuid))
998            .textAlign(TextAlign.Center)
999            .maxLines(1)
1000            .textOverflow({ overflow: TextOverflow.Ellipsis })
1001            .flexShrink(1)
1002        }
1003        .width('100%')
1004        .height(55)
1005
1006        if (this.folderItem.uuid != SysDefFolderUuid.UnClassified) {
1007          Divider()
1008            .color($r('app.color.divider_color_e4e4e4'))
1009            .strokeWidth(1)
1010        }
1011      }
1012      .padding({ left: 16 })
1013    }
1014    .id(this.isUpdate + '')
1015    .width('100%')
1016    .height(56)
1017    .visibility(FolderUtil.isFolderMoveIn(this.folderItem) ? Visibility.Visible : Visibility.None)
1018  }
1019}
1020