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