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