1/* 2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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 */ 15import MyWatcher from '../filemanager/fileFs/MyWatcher'; 16import common from '@ohos.app.ability.common'; 17import fs from '@ohos.file.fs'; 18import router from '@ohos.router'; 19import { Logger, sleep, bufferToString } from '../common/Common'; 20 21const TAG: string = '[FileIO].[WatcherFile]'; 22 23@CustomDialog 24export struct DeleteDialog { 25 @Link hitText: string 26 @Link currentIndex: number 27 controller: CustomDialogController 28 cancel: () => void = () => {} 29 confirm: (index: number) => void = () => {} 30 31 build() { 32 Column() { 33 Text(this.hitText) 34 .fontSize(20) 35 .fontColor('#182431') 36 .textAlign(TextAlign.Center) 37 .lineHeight(26) 38 .fontWeight(500) 39 .width(288) 40 .height(52) 41 .margin({ top: 24, left: 24, right: 24 }) 42 43 Flex({ justifyContent: FlexAlign.SpaceAround }) { 44 Row() { 45 Text($r('app.string.cancel')) 46 .fontSize(16) 47 .fontColor('#007DFF') 48 .textAlign(TextAlign.Center) 49 .lineHeight(22) 50 .fontWeight(500) 51 .width(136) 52 .backgroundColor(0xffffff) 53 .onClick(() => { 54 this.controller.close() 55 this.cancel() 56 }) 57 Text('|') 58 .backgroundColor(0xffffff) 59 .fontColor(Color.Gray) 60 .height(24) 61 Text($r('app.string.deleteFile')) 62 .fontSize(16) 63 .fontColor('#FA2A2D') 64 .textAlign(TextAlign.Center) 65 .lineHeight(22) 66 .fontWeight(500) 67 .width(136) 68 .backgroundColor(0xffffff) 69 .id('deleteWatcher') 70 .onClick(() => { 71 this.controller.close() 72 this.confirm(this.currentIndex) 73 }) 74 } 75 } 76 .margin({ top: 9, bottom: 25 }) 77 } 78 .backgroundColor(0xffffff) 79 .width('80%') 80 .height(132) 81 } 82} 83 84@Entry 85@Component 86struct Watcher { 87 @State message: Resource = $r('app.string.watcherFileText'); 88 @State myContext: Context = getContext(this) as common.UIAbilityContext; 89 @State inputNameValue: string = 'text.txt'; 90 @State inputContentValue: string = 'abcdefg'; 91 @State currentIndex: number = 1; 92 @State currentDelFileName: string = ''; 93 @State currentFileName: string = ''; 94 @State currentFileSize: number = 0; 95 @State currentFileContent: string = ''; 96 @State eachEvent: string = ''; 97 @State isFromEdit: boolean = false; 98 @State editFlag: boolean = true; 99 @State watcherEvent: Array<string> = [ 100 'IN_ACCESS', 101 'IN_MODIFY', 102 'IN_ATTRIB', 103 'IN_CLOSE_WRITE', 104 'IN_CLOSE_NOWRITE', 105 'IN_OPEN', 106 'IN_MOVED_FROM', 107 'IN_MOVED_TO', 108 'IN_CREATE', 109 'IN_DELETE', 110 'IN_DELETE_SELF', 111 'IN_MOVE_SELF', 112 ]; 113 @State filePathSize: Array<number> = []; 114 @State showFilePath: Array<string> = []; 115 @StorageLink('eventLog') eventLog: string = 'unknown'; 116 @StorageLink('fileNameLog') fileNameLog: string = 'unknown'; 117 @StorageLink('cookieLog') cookieLog: string = 'unknown'; 118 @StorageLink('newFileName') newFileName: string = ''; 119 @StorageLink('newFileContent') newFileContent: string = ''; 120 @StorageLink('eventArray') eventArray: Array<string> = []; 121 @StorageLink('addIndex') addIndex: number = 10; 122 public baseDir: string = AppStorage.get<string>('sanBoxFileDir') as string; 123 124 @Builder itemEnd(index: number) { // 侧滑后尾端出现的组件 125 Row() { 126 Image($r('app.media.ic_edit')) 127 .width(40) 128 .height(40) 129 .margin({ left: 16, right: 8 }) 130 .id('editFile') 131 .onClick(() => { 132 this.currentIndex = index; 133 this.currentFileName = this.showFilePath[index]; 134 let length = this.currentFileName.length; 135 this.currentFileName = this.currentFileName.substring(0, length - 4); 136 let filePath = this.baseDir + '/watcherDir/' + this.showFilePath[index]; 137 this.currentFileSize = fs.statSync(filePath).size; 138 let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE); 139 let buf = new ArrayBuffer(4096); 140 fs.readSync(file.fd, buf, { 141 offset: 0 142 }); 143 this.currentFileContent = bufferToString(buf); 144 router.pushUrl({ 145 url: 'pages/EditFile', 146 params: { 147 fileName: this.currentFileName, 148 fileSize: this.currentFileSize, 149 fileContent: this.currentFileContent, 150 } 151 }, router.RouterMode.Standard); 152 153 }); 154 155 Image($r('app.media.ic_delete')) 156 .width(40) 157 .height(40) 158 .margin(1) 159 .id('deleteFile') 160 .onClick(() => { 161 this.currentDelFileName = this.showFilePath[index]; 162 this.currentIndex = index; 163 let lastIndex = this.currentDelFileName.length - 4; 164 let isDelDile = AppStorage.get<string>('isDelFile') as string; 165 this.currentDelFileName = isDelDile + this.currentDelFileName.substring(0, lastIndex) + '?'; 166 this.deleteDialog.open(); 167 }); 168 } 169 .padding(1) 170 .justifyContent(FlexAlign.SpaceEvenly) 171 } 172 173 private select: number = 1; 174 private selectDel: number = 1; 175 private isDelStr: Resource = $r('app.string.isDelFile'); 176 myWatcher: MyWatcher = new MyWatcher(); 177 scroller: Scroller = new Scroller(); 178 deleteDialog: CustomDialogController = new CustomDialogController({ 179 builder: DeleteDialog({ 180 hitText: $currentDelFileName, 181 cancel: this.onCancel, 182 confirm: (index: number): void => this.onDelete(index), 183 currentIndex: $currentIndex, 184 }), 185 cancel: () => {}, 186 alignment: DialogAlignment.Bottom, 187 offset: { dx: 0, dy: -12 }, 188 autoCancel: true 189 }) 190 191 onCancel(): void { 192 Logger.info('cancel'); 193 }; 194 195 onDelete(index: number): void { 196 this.myWatcher.deleteFileToWatcher(this.showFilePath[index]); 197 this.filePathSize.splice(index, 1); 198 this.showFilePath.splice(index, 1); 199 } 200 201 onPageShow(): void { 202 Logger.info('aboutToDisappear eventArray: ' + this.eventArray.length); 203 let filePathDir = this.baseDir + '/watcherDir'; 204 Logger.info('filePathDir = ' + filePathDir); 205 let filenames = fs.listFileSync(filePathDir); 206 Logger.info('listFile succeed'); 207 for (let i = 0; i < filenames.length; i++) { 208 Logger.info('filename: %s', filenames[i]); 209 this.showFilePath[i] = filenames[i]; 210 let filePath = filePathDir + '/' + filenames[i]; 211 this.filePathSize[i] = fs.statSync(filePath).size; 212 } 213 } 214 215 onPageHide(): void { 216 Logger.info('onPageHide eventArray: ' + this.eventArray.length); 217 } 218 219 aboutToDisappear(): void { 220 try { 221 for (let i = 0; i < this.myWatcher.watcherList.length; i++) { 222 Logger.info('aboutToDisappear this.myWatcher.watcherList.length: ' + this.myWatcher.watcherList.length); 223 this.myWatcher.stopWatcher(this.myWatcher.watcherList[i], i); 224 } 225 } catch (e) { 226 Logger.error('stopwatcher fail and error: ' + JSON.stringify(e)); 227 } 228 } 229 230 aboutToAppear(): void { 231 Logger.info('aboutToAppear eventArray: ' + this.eventArray.length); 232 } 233 234 build() { 235 Scroll(this.scroller) { 236 Row() { 237 Column() { 238 Row() { 239 Image($r('app.media.ic_back')) 240 .width(24) 241 .height(24) 242 .align(Alignment.Start) 243 .margin({ top: 13, bottom: 15, left: 26, right: 18 }) 244 .id('backIndex') 245 .onClick(() => { 246 router.pushUrl({ 247 url: 'pages/Index', 248 }, router.RouterMode.Standard); 249 }) 250 Text(this.message) 251 .fontSize(20) 252 .fontColor('#182431') 253 .textAlign(TextAlign.Start) 254 .lineHeight(28) 255 .fontWeight(700) 256 .margin({ top: 13, bottom: 15 }) 257 258 } 259 .width('100%') 260 .height(56) 261 .backgroundColor('#f1f3f5') 262 .align(Alignment.Start) 263 264 Flex({ direction: FlexDirection.Column }) { 265 Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween }) { 266 Row() { 267 Text($r('app.string.watcherTitleText')) 268 .fontSize(14) 269 .margin({ top: 19.5, bottom: 9.5 }) 270 .lineHeight(19) 271 .width(176) 272 .fontColor('#182431') 273 .fontWeight(500) 274 .textAlign(TextAlign.Start) 275 .backgroundColor('#f1f3f5') 276 .opacity(0.6) 277 } 278 .width('61%') 279 .padding({ left: 24, right: 52 }) 280 .backgroundColor('#f1f3f5') 281 282 Row() { 283 Text($r('app.string.addFile')) 284 .margin({ top: 19.5, bottom: 9.5 }) 285 .fontSize(14) 286 .height(48) 287 .backgroundColor('#f1f3f5') 288 .fontColor('#007DFF') 289 .textAlign(TextAlign.End) 290 .fontWeight(500) 291 .width(84) 292 .id('addFile') 293 .onClick(() => { 294 let filePathDir = this.baseDir + '/watcherDir/'; 295 let fileName = `TestFile${this.addIndex}.txt`; 296 this.addIndex++; 297 this.myWatcher.addFileToWatcher(fileName); 298 let filePath = filePathDir + fileName; 299 let res = fs.accessSync(filePath); 300 this.showFilePath.push(fileName); 301 if (res) { 302 this.filePathSize.push(fs.statSync(filePath).size); 303 Logger.info('addFileToWatcher this.filePathSize size = ' + fs.statSync(filePath).size); 304 } 305 }) 306 } 307 .justifyContent(FlexAlign.SpaceBetween) 308 .height(48) 309 .margin({ right: 24 }) 310 .width('30%') 311 .backgroundColor('#f1f3f5') 312 } 313 .width('100%') 314 .backgroundColor('#f1f3f5') 315 316 Column() { 317 List({ space: 12, initialIndex: 0 }) { 318 ForEach(this.showFilePath, (item: string, index?: number) => { 319 ListItem() { 320 Row() { 321 Text(item) 322 .fontSize(16) 323 .fontColor('#182431') 324 .width('70%') 325 .lineHeight(22) 326 .textAlign(TextAlign.Start) 327 .fontWeight(500) 328 .margin({ left: 12 }) 329 .borderRadius(10) 330 .backgroundColor(0xFFFFFF) 331 .id('item' + index) 332 if (index != undefined) { 333 Text(JSON.stringify(this.filePathSize[index]) + 'B') 334 .fontSize(14) 335 .width('24.5%') 336 .lineHeight(19) 337 .textAlign(TextAlign.End) 338 .fontColor('#182431') 339 .fontWeight(400) 340 .opacity(0.6) 341 .margin({ right: 12 }) 342 .borderRadius(10) 343 .backgroundColor(0xFFFFFF) 344 } 345 } 346 .borderRadius(20) 347 .width('94%') 348 .height(56) 349 .backgroundColor(0xFFFFFF) 350 } 351 .swipeAction({ end: () : void => this.itemEnd(index) }) // 设置左滑属性 352 }, (item: string) => item) 353 } 354 .id('list') 355 .alignListItem(ListItemAlign.Center) 356 .scrollBar(BarState.Auto) 357 } 358 .padding({ top: 5 }) 359 .backgroundColor('#f1f3f5') 360 .width('100%') 361 .height(436) 362 .align(Alignment.Center) 363 364 Column() { 365 Row() { 366 Text($r('app.string.logTitle')) 367 .fontSize(14) 368 .fontColor('#182431') 369 .textAlign(TextAlign.Start) 370 .lineHeight(19) 371 .fontWeight(500) 372 .margin({ top: 19.5, left: 24 }) 373 .width(176) 374 .opacity(0.6) 375 } 376 .width('100%') 377 .align(Alignment.Start) 378 379 Column() { 380 Column() { 381 Text(`event: ${this.eventLog}`) 382 .fontSize(16) 383 .fontColor('#182431') 384 .fontWeight(400) 385 .width('100%') 386 Text(`fileName: ${this.fileNameLog}`) 387 .fontSize(16) 388 .fontColor('#182431') 389 .fontWeight(400) 390 .width('100%') 391 Text(`cookie: ${this.cookieLog}`) 392 .fontSize(16) 393 .fontColor('#182431') 394 .fontWeight(400) 395 .width('100%') 396 } 397 .margin({ top: 8, left: 12, right: 12, bottom: 8 }) 398 .height(64) 399 } 400 .borderRadius(20) 401 .height(80) 402 .margin({ top: 9.5, left: 16, right: 16 }) 403 .backgroundColor('#ffffff') 404 405 Row({ space: 2 }) { 406 Column() { 407 Button($r('app.string.stopWatcher')) 408 .fontSize(16) 409 .width(144) 410 .height(40) 411 .backgroundColor('#e6e9eb') 412 .fontColor('#007DFF') 413 .fontWeight(500) 414 .margin({ right: 24 }) 415 .id('stopWatcher') 416 .onClick(() => { 417 let showEventArray : string[] = []; 418 Logger.info('onClick this.eventArray.length = ' + this.eventArray.length); 419 let j = 0; 420 for (let i = 0; i < this.eventArray.length; i++) { 421 Logger.info('onClick this.eventArray[' + i + '] = ' + this.eventArray[i]); 422 if (this.eventArray[i] === 'test') { 423 continue; 424 } 425 Logger.info('onClick2 this.eventArray[' + i + '] = ' + this.eventArray[i]); 426 showEventArray[j] = this.eventArray[i]; 427 j++; 428 Logger.info('onClick showEventArray[' + j + '] = ' + showEventArray[j]); 429 } 430 if (showEventArray.length === 0) { 431 AlertDialog.show({ 432 message: '当前无监听,请先添加监听' 433 }) 434 return; 435 } 436 TextPickerDialog.show({ 437 range: showEventArray, 438 selected: this.selectDel, 439 onAccept: (value: TextPickerResult) => { 440 this.selectDel = Number(value.index); 441 Logger.info('TextPickerDialog:onChange() this.selectDel = ' + this.selectDel); 442 Logger.info('TextPickerDialog:onChange() value = ' + JSON.stringify(value)); 443 this.myWatcher.stopWatcher(this.myWatcher.watcherList[this.selectDel], this.selectDel); 444 this.eventArray.splice(this.selectDel, 1); 445 showEventArray.splice(this.selectDel, 1); 446 }, 447 }) 448 }) 449 } 450 .width('50%') 451 .align(Alignment.Start) 452 453 Column() { 454 Button($r('app.string.addWatcher')) 455 .fontSize(16) 456 .width(144) 457 .height(40) 458 .fontColor('#FFFFFF') 459 .fontWeight(500) 460 .id('addWatcher') 461 .onClick(() => { 462 TextPickerDialog.show({ 463 range: this.watcherEvent, 464 selected: this.select, 465 onAccept: (value: TextPickerResult) => { 466 this.select = Number(value.index); 467 Logger.info('TextPickerDialog:onChange() this.select = ' + this.select); 468 Logger.info('TextPickerDialog:onChange() value = ' + JSON.stringify(value)); 469 Logger.info('TextPickerDialog:onChange() this.select = ' + this.select); 470 this.eachEvent = this.watcherEvent[this.select]; 471 Logger.info('TextPickerDialog:onChange() this.eachEvent = ' + this.eachEvent); 472 this.myWatcher.startWatcher(this.eachEvent); 473 Logger.info(`onSelect-${this.eachEvent} end`); 474 this.eventArray.push(this.eachEvent); // 新增列表项数据 475 }, 476 }) 477 }) 478 } 479 .width('50%') 480 .align(Alignment.End) 481 } 482 .align(Alignment.Center) 483 .width('70%') 484 .margin({ top: 24, left: 24, right: 24, bottom: 24 }) 485 } 486 .backgroundColor('#f1f3f5') 487 .width('100%') 488 .height(216) 489 } 490 .width('100%') 491 } 492 .width('100%') 493 } 494 .height('100%') 495 } 496 .id('scroller') 497 } 498}