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 */
15
16import FolderData from '@ohos/utils/src/main/ets/default/model/databaseModel/FolderData'
17import NoteData from '@ohos/utils/src/main/ets/default/model/databaseModel/NoteData'
18import {
19  SysDefFolderUuid,
20  TableName,
21  FolderType,
22  FolderTableColumn,
23  NoteTableColumn,
24  Delete,
25  DeleteFileType
26} from '@ohos/utils/src/main/ets/default/model/databaseModel/EnumData'
27import { NewOrEditFolderDialog, DeleteDialog } from './CusDialogComp'
28import RdbStoreUtil from '@ohos/utils/src/main/ets/default/baseUtil/RdbStoreUtil'
29import FolderUtil from '@ohos/utils/src/main/ets/default/baseUtil/FolderUtil'
30import NoteUtil from '@ohos/utils/src/main/ets/default/baseUtil/NoteUtil'
31import { LogUtil } from '@ohos/utils/src/main/ets/default/baseUtil/LogUtil'
32import webview from '@ohos.web.webview';
33
34// Folder list component
35@Component
36export struct FolderListComp {
37  @StorageLink('AllFolderArray') AllFolderArray: FolderData[] = AppStorage.Link('AllFolderArray')
38  @Consume('SectionStatus') sectionStatus: number
39  @Consume('ExpandStatus') expandStatus: boolean // 笔记本折叠展开状态
40  @StorageLink('breakPoint') breakPoints: string = 'lg'
41  controllerShow: webview.WebviewController = new webview.WebviewController();
42  TAG = "FolderListComp"
43  @Consume('AsideWidth') asideWidth: number
44
45  build() {
46    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween }) {
47      Column() {
48        Column() {
49          Image($r("app.media.suojin"))
50            .height(24)
51            .width(24)
52            .responseRegion({ x: -15.0, y: -15.0, width: 54, height: 54 })
53            .onClick(() => {
54              if (this.breakPoints == 'sm' || this.breakPoints == 'md') {
55                animateTo({ duration: 200 }, () => {
56                  this.expandStatus = !this.expandStatus
57                })
58              } else {
59                this.asideWidth = 0
60                this.sectionStatus = (this.sectionStatus == 3 ? 2 : 3)
61                // save continue data
62                AppStorage.SetOrCreate<number>('ContinueSection', this.sectionStatus)
63                LogUtil.info(this.TAG, "FolderListComp, set continue section success")
64              }
65            })
66        }
67        .alignItems(HorizontalAlign.Start)
68        .width("100%")
69        .margin({ top: 28 })
70        .padding({ left: 24 })
71        .flexGrow(1)
72
73        NoteAndCreateComp()
74        // center
75        List() {
76          ForEach(this.AllFolderArray, (folderItem: FolderData) => {
77            ListItem() {
78              if (!FolderUtil.isBottomFixedFolder(folderItem)) {
79                FolderItemComp({ folderItem: folderItem, controllerShow: this.controllerShow })
80              }
81            }
82          }, folderItem => folderItem.name.toString())
83        }
84        .width('100%')
85        .height(500)
86        .margin({ bottom: 120 })
87        .padding({ left: 12, right: 12 })
88        .flexGrow(1)
89      }
90
91
92      Column() {
93        FolderItemComp({
94          folderItem: FolderUtil.getFolderData(AppStorage.Get('AllFolderArray'), SysDefFolderUuid.MyFavorites),
95          controllerShow: this.controllerShow
96        })
97        FolderItemComp({
98          folderItem: FolderUtil.getFolderData(AppStorage.Get('AllFolderArray'), SysDefFolderUuid.RecentDeletes),
99          controllerShow: this.controllerShow
100        })
101      }
102      .backgroundColor($r("app.color.folderlist_bgcolor_f1f3f5"))
103      .flexGrow(0)
104      .width("100%")
105      .padding({ left: 12, right: 12, bottom: 24 })
106    }
107    .height("100%")
108    .backgroundColor($r('app.color.folder_color_d6d6d6'))
109    .backgroundBlurStyle(BlurStyle.Thick)
110  }
111
112  aboutToAppear(): void {
113    LogUtil.info(this.TAG, "aboutToAppear")
114  }
115
116  aboutToDisappear(): void {
117    LogUtil.info(this.TAG, "aboutToDisappear")
118  }
119}
120
121@Component
122export struct NoteAndCreateComp {
123  @StorageLink('AllFolderArray') AllFolderArray: FolderData[] = AppStorage.Link('AllFolderArray')
124  @Consume('SelectedColor') selectedColor: string
125  @Consume('PortraitModel') portraitModel: boolean
126  folderCreateDialogCtl: CustomDialogController = new CustomDialogController({
127    builder: NewOrEditFolderDialog({ confirm: this.onCreateConfirm.bind(this), dialogType: 0 }),
128    alignment: DialogAlignment.Center,
129    autoCancel: false,
130    customStyle: true,
131  })
132  folderCreateDialogCtlBottom: CustomDialogController = new CustomDialogController({
133    builder: NewOrEditFolderDialog({ confirm: this.onCreateConfirm.bind(this), dialogType: 0 }),
134    alignment: DialogAlignment.Bottom,
135    autoCancel: false,
136    customStyle: true,
137  })
138
139  aboutToDisappear() {
140    this.folderCreateDialogCtl = null
141    this.folderCreateDialogCtlBottom = null
142  }
143
144  onCreateConfirm(color: string, name: string) {
145    let folderData = new FolderData(0, name, new Date().getTime() + "", color, FolderType.CusDef, Delete.No, new Date().getTime(), new Date().getTime()) // 新的的笔记本都是自定义类型 type为1
146    this.AllFolderArray.push(folderData)
147    // insert folder to db
148    RdbStoreUtil.insert(TableName.FolderTable, folderData.toFolderObject(), null)
149    AppStorage.SetOrCreate('isUpdate', true)
150  }
151
152  build() {
153    Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) {
154      Row() {
155        Text($r("app.string.note"))
156          .fontSize(20)
157          .fontWeight(FontWeight.Bold)
158      }.width(102)
159
160      Row() {
161        Text($r("app.string.create"))
162          .fontSize(14)
163          .fontColor($r("app.color.text_color_f86d05"))
164          .onClick(() => {
165            this.selectedColor = "#e84026" // 新建的时候选中第一个颜色
166            if (this.portraitModel) {
167              this.folderCreateDialogCtlBottom.open()
168            } else {
169              this.folderCreateDialogCtl.open()
170            }
171          }).padding({ right: 0 })
172      }.width(50)
173    }.width("100%")
174    .margin({ top: 8 })
175    .padding({ left: 24 })
176    .height(56)
177  }
178}
179
180@Component
181struct FolderItemComp {
182  @State folderItem: FolderData = new FolderData(0, "", new Date().getTime() + "", "", FolderType.CusDef, Delete.No, new Date().getTime(), new Date().getTime())
183  @StorageLink('AllNoteArray') AllNoteArray: NoteData[] = []
184  @StorageLink('AllFolderArray') AllFolderArray: FolderData[] = []
185  @StorageLink('CheckedNoteArray') CheckedNoteArray: NoteData[] = []
186  @Consume('SelectedFolderData') selectedFolderData: FolderData
187  @Consume('SelectedNoteData') selectedNoteData: NoteData
188  @Consume('RefreshFlag') refreshFlag: number
189  @Consume('Longpress') longpress: boolean
190  @Consume('SelectedColor') selectedColor: string
191  @Consume('PortraitModel') portraitModel: boolean
192  controllerShow: WebviewController
193  @State isLongPress: boolean = false
194  TAG = "FolderItemComp"
195  @StorageLink('isUpdate') isUpdate: boolean = false
196  // Folder Edit Dialog
197  folderEditDialogCtl: CustomDialogController = new CustomDialogController({
198    builder: NewOrEditFolderDialog({
199      editFolderUuid: this.folderItem.uuid,
200      confirm: this.onEditConfirm.bind(this),
201      dialogType: 1
202    }),
203    alignment: DialogAlignment.Center,
204    autoCancel: false,
205    customStyle: true,
206  })
207  // Folder Edit Dialog for portrait model
208  folderEditDialogCtlBottom: CustomDialogController = new CustomDialogController({
209    builder: NewOrEditFolderDialog({
210      editFolderUuid: this.folderItem.uuid,
211      confirm: this.onEditConfirm.bind(this),
212      dialogType: 1
213    }),
214    alignment: DialogAlignment.Bottom,
215    autoCancel: false,
216    customStyle: true,
217  })
218
219  aboutToDisappear() {
220    this.folderEditDialogCtl = null
221    this.folderEditDialogCtlBottom = null
222    this.folderDeleteDialogCtl = null
223    this.folderDeleteDialogCtlBottom = null
224    this.folderCreateDialogCtl = null
225    this.folderCreateDialogCtlBottom = null
226  }
227
228  // Folder Edit Callback
229  onEditConfirm(color: string, name: string) {
230    this.folderItem.color = color
231    this.folderItem.name = name
232    this.folderItem.folder_type = FolderType.CusDef
233    // update folder to db
234    let predicates_folder = RdbStoreUtil.getRdbPredicates(TableName.FolderTable)
235    predicates_folder.equalTo(FolderTableColumn.Uuid, this.folderItem.uuid)
236    RdbStoreUtil.update(this.folderItem.toFolderObject(), predicates_folder, null)
237    this.isUpdate = true
238  }
239  // Folder Delete Dialog
240  folderDeleteDialogCtl: CustomDialogController = new CustomDialogController({
241    builder: DeleteDialog({ onConfirm: this.onDeleteConfirm.bind(this), deleteFileType: DeleteFileType.FolderData }),
242    alignment: DialogAlignment.Center,
243    autoCancel: false,
244    customStyle: true,
245  })
246  // Folder Delete Dialog for portrait model
247  folderDeleteDialogCtlBottom: CustomDialogController = new CustomDialogController({
248    builder: DeleteDialog({ onConfirm: this.onDeleteConfirm.bind(this), deleteFileType: DeleteFileType.FolderData }),
249    alignment: DialogAlignment.Bottom,
250    autoCancel: false,
251    customStyle: true,
252  })
253  // Folder Delete Callback
254  onDeleteConfirm() {
255    let currentFolder = FolderUtil.getFolderData(this.AllFolderArray, this.folderItem.uuid)
256    let index = this.AllFolderArray.indexOf(currentFolder)
257    let currentNoteDataArray = NoteUtil.getNoteDataArray(AppStorage.Get('AllNoteArray'), this.folderItem.uuid)
258    let deleteNoteDataArray = NoteUtil.getNoteDataArray(AppStorage.Get('AllNoteArray'), 'sys_def_recentDeletes_uuid')
259    if (index > -1) {
260      this.AllFolderArray.splice(index, 1)
261      if (deleteNoteDataArray.length != 0) {
262        deleteNoteDataArray.forEach((noteItem: NoteData) => {
263          let folderData: FolderData = FolderUtil.getFolderData(this.AllFolderArray, noteItem.folder_uuid)
264          if (folderData == undefined) {
265            noteItem.folder_uuid = SysDefFolderUuid.UnClassified
266            // update note to db
267            let predicates_note = RdbStoreUtil.getRdbPredicates(TableName.NoteTable)
268            predicates_note.equalTo(NoteTableColumn.Uuid, noteItem.uuid)
269            RdbStoreUtil.update(noteItem.toNoteObject(), predicates_note, null)
270          }
271        })
272      }
273      if (currentNoteDataArray.length != 0) {
274        currentNoteDataArray.forEach((noteItem: NoteData) => {
275          noteItem.is_deleted = Delete.Yes
276          noteItem.folder_uuid = SysDefFolderUuid.UnClassified
277          noteItem.deleted_time = new Date().getTime()
278          // update note to db
279          let predicates_note = RdbStoreUtil.getRdbPredicates(TableName.NoteTable)
280          predicates_note.equalTo(NoteTableColumn.Uuid, noteItem.uuid)
281          RdbStoreUtil.update(noteItem.toNoteObject(), predicates_note, null)
282        })
283      }
284      // delete folder from db
285      let predicates_folder = RdbStoreUtil.getRdbPredicates(TableName.FolderTable)
286      predicates_folder.equalTo(FolderTableColumn.Uuid, this.folderItem.uuid)
287      RdbStoreUtil.delete(predicates_folder, null)
288      // update selectedFolderData and selectedNoteData
289      this.selectedFolderData = FolderUtil.getFolderData(this.AllFolderArray, SysDefFolderUuid.AllNotes)
290      this.selectedNoteData = NoteUtil.getFirstNoteData(this.AllNoteArray, SysDefFolderUuid.AllNotes)
291      if (!this.selectedNoteData) {
292        return
293      }
294      // 刷新web界面
295      if (this.portraitModel == false) {
296        try {
297          this.controllerShow.runJavaScript(
298            "RICH_EDITOR.setHtml('" + this.selectedNoteData.content_text + "')"
299          )
300          LogUtil.info(this.TAG, `runJavaScript success.`);
301        } catch (error) {
302          LogUtil.error(this.TAG, `runJavaScript failed.code:${JSON.stringify(error.code)},message:${JSON.stringify(error.message)}`);
303        }
304      }
305      // save continue data
306      let continueNote: string = JSON.stringify(this.selectedNoteData.toNoteObject())
307      AppStorage.SetOrCreate<string>('ContinueNote', continueNote)
308      LogUtil.info(this.TAG, "onDeleteConfirm, set continue note success")
309    }
310    this.isUpdate = true
311  }
312  // Folder Create Dialog
313  folderCreateDialogCtl: CustomDialogController = new CustomDialogController({
314    builder: NewOrEditFolderDialog({ confirm: this.onCreateConfirm.bind(this), dialogType: 0 }),
315    alignment: DialogAlignment.Center,
316    autoCancel: false,
317    customStyle: true,
318  })
319  // Folder Create Dialog for portrait model
320  folderCreateDialogCtlBottom: CustomDialogController = new CustomDialogController({
321    builder: NewOrEditFolderDialog({ confirm: this.onCreateConfirm.bind(this), dialogType: 0 }),
322    alignment: DialogAlignment.Bottom,
323    autoCancel: false,
324    customStyle: true,
325  })
326  // Folder Create Callback
327  onCreateConfirm(color: string, name: string) {
328    let folderData = new FolderData(0, name, new Date().getTime() + "", color, FolderType.CusDef, Delete.No, new Date().getTime(), new Date().getTime()) // 新的的笔记本都是自定义类型 type为1
329    this.AllFolderArray.push(folderData)
330    // insert folder to db
331    RdbStoreUtil.insert(TableName.FolderTable, folderData.toFolderObject(), null)
332    this.isUpdate = true
333  }
334
335  @Builder menuBuilder() {
336    Column({ space: 1 }) {
337      Text($r("app.string.editFolder"))
338        .width(124)
339        .height(48)
340        .padding({ top: 13, bottom: 13 })
341        .fontSize(16)
342        .fontColor($r("app.color.folder_color_182431"))
343        .onClick(() => {
344          this.selectedColor = this.folderItem.color
345          if (this.portraitModel) {
346            this.folderEditDialogCtlBottom.open()
347          } else {
348            this.folderEditDialogCtl.open()
349          }
350          ContextMenu.close()
351        })
352      Divider()
353        .color($r("app.color.divider_color_e4e4e4"))
354        .strokeWidth(1)
355      Text($r("app.string.deleteFolder"))
356        .width(124)
357        .height(48)
358        .padding({ top: 13, bottom: 14 })
359        .fontSize(16)
360        .fontColor($r("app.color.folder_color_182431"))
361        .onClick(() => {
362          if (this.portraitModel) {
363            this.folderDeleteDialogCtlBottom.open()
364          } else {
365            this.folderDeleteDialogCtl.open()
366          }
367          ContextMenu.close()
368        })
369      Divider()
370        .color($r("app.color.divider_color_e4e4e4"))
371        .strokeWidth(1)
372      Text($r("app.string.createFolder"))
373        .width(124)
374        .height(48)
375        .padding({ top: 13, bottom: 15 })
376        .fontSize(16)
377        .fontColor($r("app.color.folder_color_182431"))
378        .onClick(() => {
379          this.selectedColor = "#e84026" // 新建的时候选中第一个颜色
380          if (this.portraitModel) {
381            this.folderCreateDialogCtlBottom.open()
382          } else {
383            this.folderCreateDialogCtl.open()
384          }
385          ContextMenu.close()
386        })
387    }
388    .width(156)
389    .height(154)
390    .padding({ top: 4, bottom: 4, left: 16, right: 16 })
391    .borderRadius(16)
392    .backgroundColor($r("app.color.press_folder_bg_color"))
393  }
394
395  build() {
396    Flex() {
397      if (this.folderItem?.folder_type == FolderType.CusDef) {
398        Flex({ alignItems: ItemAlign.Center, wrap: FlexWrap.NoWrap, justifyContent: FlexAlign.SpaceBetween }) {
399          Row() {
400            Image(FolderUtil.getFolderIcon(this.folderItem.uuid))
401              .id(this.isUpdate + '')
402              .objectFit(ImageFit.Fill)
403              .width(24)
404              .height(24)
405              .fillColor(FolderUtil.getFolderIconColor(this.AllFolderArray, this.folderItem.uuid, this.selectedFolderData.uuid == this.folderItem.uuid))
406              .margin({ right: 16 })
407            Text(FolderUtil.getFolderText(this.folderItem))
408              .id(this.isUpdate + '')
409              .fontWeight(FontWeight.Medium)
410              .fontSize(16)
411              .textAlign(TextAlign.Center)
412              .maxLines(1)
413              .textOverflow({ overflow: TextOverflow.Ellipsis })
414              .flexShrink(1)
415              .fontColor(FolderUtil.getFolderTextColor(this.selectedFolderData.uuid == this.folderItem.uuid))
416            Text(JSON.stringify(this.refreshFlag))
417              .visibility(Visibility.None) // 用于强制刷新使用
418          }.width(118)
419
420          Text(FolderUtil.getNoteCount(AppStorage.Get('AllNoteArray'), this.folderItem.uuid).toString())
421            .id(this.isUpdate + '')
422            .fontWeight(FontWeight.Regular)
423            .fontSize(14)
424            .textAlign(TextAlign.Center)
425        }
426        .width('100%')
427        .borderRadius(12)
428        .height(56)
429        .padding({ left: 12, right: 12 })
430        .backgroundColor(this.isLongPress ? $r("app.color.folder_color_19182431") : this.selectedFolderData.uuid == this.folderItem.uuid
431                                                                                      ? $r("app.color.folder_color_ffffff") : "#00FFFFFF")
432        .bindContextMenu(this.menuBuilder, ResponseType.LongPress)
433        .bindContextMenu(this.menuBuilder, ResponseType.RightClick)
434        .onClick(() => {
435          if (this.longpress) {
436            this.longpress = false
437            NoteUtil.unsetAllNotesChecked(this.CheckedNoteArray)
438          } else {
439            this.selectedFolderData = this.folderItem
440            this.selectedNoteData = NoteUtil.getFirstNoteData(AppStorage.Get('AllNoteArray'), this.folderItem.uuid)
441            if (!this.selectedNoteData) {
442              return
443            }
444            // 刷新web界面
445            if (this.portraitModel == false) {
446              try {
447                this.controllerShow.runJavaScript(
448                  "RICH_EDITOR.setHtml('" + this.selectedNoteData.content_text + "')"
449                );
450                LogUtil.info(this.TAG, `onClick runJavaScript setHtml success.`);
451              } catch (error) {
452                LogUtil.error(this.TAG, `onClick runJavaScript setHtml failed,code:${JSON.stringify(error.code)},
453                  message:${JSON.stringify(error.message)}.`);
454              }
455            }
456            // save continue data
457            let continueNote: string = JSON.stringify(this.selectedNoteData.toNoteObject())
458            AppStorage.SetOrCreate<string>('ContinueNote', continueNote)
459            AppStorage.SetOrCreate('ContinueSection', 3)
460            LogUtil.info(this.TAG, "FolderItemComp, set continue note success")
461          }
462          NoteUtil.refreshAll()
463        })
464      } else {
465        Flex({ alignItems: ItemAlign.Center, wrap: FlexWrap.NoWrap, justifyContent: FlexAlign.SpaceBetween }) {
466          Row() {
467            Image(FolderUtil.getFolderIcon(this.folderItem.uuid))
468              .id(this.isUpdate + '')
469              .objectFit(ImageFit.Fill)
470              .width(24)
471              .height(24)
472              .fillColor(this.isUpdate ? FolderUtil.getFolderIconColor(this.AllFolderArray, this.folderItem.uuid, this.selectedFolderData.uuid == this.folderItem.uuid) : FolderUtil.getFolderIconColor(this.AllFolderArray, this.folderItem.uuid, this.selectedFolderData.uuid == this.folderItem.uuid))
473              .margin({ right: 16 })
474            Text(FolderUtil.getFolderText(this.folderItem))
475              .id(this.isUpdate + '')
476              .fontWeight(FontWeight.Medium)
477              .fontSize(16)
478              .textAlign(TextAlign.Center)
479              .maxLines(1)
480              .textOverflow({ overflow: TextOverflow.Ellipsis })
481              .flexShrink(1)
482              .fontColor(FolderUtil.getFolderTextColor(this.selectedFolderData.uuid == this.folderItem.uuid))
483            Text(JSON.stringify(this.refreshFlag))
484              .visibility(Visibility.None) // 用于强制刷新使用
485          }.width(118)
486
487          Text(FolderUtil.getNoteCount(AppStorage.Get('AllNoteArray'), this.folderItem.uuid).toString())
488            .id(this.isUpdate + '')
489            .fontWeight(FontWeight.Regular)
490            .fontSize(14)
491            .textAlign(TextAlign.Center)
492        }
493        .width('100%')
494        .borderRadius(12)
495        .height(56)
496        .padding({ left: 12, right: 12 })
497        .backgroundColor(this.isLongPress ? $r("app.color.folder_color_19182431") : this.selectedFolderData.uuid == this.folderItem.uuid
498                                                                                      ? $r("app.color.folder_color_ffffff") : "#00FFFFFF")
499        .onClick(() => {
500          if (this.longpress) {
501            this.longpress = false
502            NoteUtil.unsetAllNotesChecked(this.CheckedNoteArray)
503          } else {
504            this.selectedFolderData = this.folderItem
505            this.selectedNoteData = NoteUtil.getFirstNoteData(AppStorage.Get('AllNoteArray'), this.folderItem.uuid)
506            if (!this.selectedNoteData) {
507              return
508            }
509            // 刷新web界面
510            if (this.portraitModel == false) {
511              try {
512                this.controllerShow.runJavaScript(
513                  "RICH_EDITOR.setHtml('" + this.selectedNoteData.content_text + "')"
514                );
515                LogUtil.info(this.TAG, `else runJavaScript setHtml success.`);
516              } catch (error) {
517                LogUtil.info(this.TAG, `else runJavaScript setHtml failed.code:${JSON.stringify(error.code)},
518                  message:${JSON.stringify(error.message)}`);
519              }
520            }
521            // save continue data
522            let continueNote: string = JSON.stringify(this.selectedNoteData.toNoteObject())
523            AppStorage.SetOrCreate<string>('ContinueNote', continueNote)
524            AppStorage.SetOrCreate('ContinueSection', 3)
525            LogUtil.info(this.TAG, "FolderItemComp, set continue note success")
526          }
527          NoteUtil.refreshAll()
528        })
529      }
530    }
531    .width('100%')
532    .height(56)
533    .parallelGesture(
534    GestureGroup(GestureMode.Exclusive,
535    LongPressGesture()
536      .onAction(() => {
537        this.isLongPress = true
538        this.refreshFlag = (this.refreshFlag == 0 ? 1 : 0)
539      })
540      .onActionEnd(() => {
541        this.isLongPress = false
542        this.refreshFlag = (this.refreshFlag == 0 ? 1 : 0)
543      })
544    )
545    )
546  }
547}