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) => 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('sanBoxFileDir'); 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('isDelFile'); 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: this.onDelete.bind(this), 183 currentIndex: $currentIndex, 184 }), 185 cancel: () => void {}, 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, index) => { 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 Text(JSON.stringify(this.filePathSize[index]) + 'B') 333 .fontSize(14) 334 .width('24.5%') 335 .lineHeight(19) 336 .textAlign(TextAlign.End) 337 .fontColor('#182431') 338 .fontWeight(400) 339 .opacity(0.6) 340 .margin({ right: 12 }) 341 .borderRadius(10) 342 .backgroundColor(0xFFFFFF) 343 } 344 .borderRadius(20) 345 .width('94%') 346 .height(56) 347 .backgroundColor(0xFFFFFF) 348 } 349 .swipeAction({ end: this.itemEnd.bind(this, index) }) // 设置左滑属性 350 }, item => item) 351 } 352 .id('list') 353 .alignListItem(ListItemAlign.Center) 354 .scrollBar(BarState.Auto) 355 } 356 .padding({ top: 5 }) 357 .backgroundColor('#f1f3f5') 358 .width('100%') 359 .height(436) 360 .align(Alignment.Center) 361 362 Column() { 363 Row() { 364 Text($r('app.string.logTitle')) 365 .fontSize(14) 366 .fontColor('#182431') 367 .textAlign(TextAlign.Start) 368 .lineHeight(19) 369 .fontWeight(500) 370 .margin({ top: 19.5, left: 24 }) 371 .width(176) 372 .opacity(0.6) 373 } 374 .width('100%') 375 .align(Alignment.Start) 376 377 Column() { 378 Column() { 379 Text(`event: ${this.eventLog}`) 380 .fontSize(16) 381 .fontColor('#182431') 382 .fontWeight(400) 383 .width('100%') 384 Text(`fileName: ${this.fileNameLog}`) 385 .fontSize(16) 386 .fontColor('#182431') 387 .fontWeight(400) 388 .width('100%') 389 Text(`cookie: ${this.cookieLog}`) 390 .fontSize(16) 391 .fontColor('#182431') 392 .fontWeight(400) 393 .width('100%') 394 } 395 .margin({ top: 8, left: 12, right: 12, bottom: 8 }) 396 .height(64) 397 } 398 .borderRadius(20) 399 .height(80) 400 .margin({ top: 9.5, left: 16, right: 16 }) 401 .backgroundColor('#ffffff') 402 403 Row({ space: 2 }) { 404 Column() { 405 Button($r('app.string.stopWatcher')) 406 .fontSize(16) 407 .width(144) 408 .height(40) 409 .backgroundColor('#e6e9eb') 410 .fontColor('#007DFF') 411 .fontWeight(500) 412 .margin({ right: 24 }) 413 .id('stopWatcher') 414 .onClick(() => { 415 let showEventArray = []; 416 Logger.info('onClick this.eventArray.length = ' + this.eventArray.length); 417 let j = 0; 418 for (let i = 0; i < this.eventArray.length; i++) { 419 Logger.info('onClick this.eventArray[' + i + '] = ' + this.eventArray[i]); 420 if (this.eventArray[i] === 'test') { 421 continue; 422 } 423 Logger.info('onClick2 this.eventArray[' + i + '] = ' + this.eventArray[i]); 424 showEventArray[j] = this.eventArray[i]; 425 j++; 426 Logger.info('onClick showEventArray[' + j + '] = ' + showEventArray[j]); 427 } 428 if (showEventArray.length === 0) { 429 AlertDialog.show({ 430 message: '当前无监听,请先添加监听' 431 }) 432 return; 433 } 434 TextPickerDialog.show({ 435 range: showEventArray, 436 selected: this.selectDel, 437 onAccept: (value: TextPickerResult) => { 438 this.selectDel = Number(value.index); 439 Logger.info('TextPickerDialog:onChange() this.selectDel = ' + this.selectDel); 440 Logger.info('TextPickerDialog:onChange() value = ' + JSON.stringify(value)); 441 this.myWatcher.stopWatcher(this.myWatcher.watcherList[this.selectDel], this.selectDel); 442 this.eventArray.splice(this.selectDel, 1); 443 showEventArray.splice(this.selectDel, 1); 444 }, 445 }) 446 }) 447 } 448 .width('50%') 449 .align(Alignment.Start) 450 451 Column() { 452 Button($r('app.string.addWatcher')) 453 .fontSize(16) 454 .width(144) 455 .height(40) 456 .fontColor('#FFFFFF') 457 .fontWeight(500) 458 .id('addWatcher') 459 .onClick(() => { 460 TextPickerDialog.show({ 461 range: this.watcherEvent, 462 selected: this.select, 463 onAccept: (value: TextPickerResult) => { 464 this.select = Number(value.index); 465 Logger.info('TextPickerDialog:onChange() this.select = ' + this.select); 466 Logger.info('TextPickerDialog:onChange() value = ' + JSON.stringify(value)); 467 Logger.info('TextPickerDialog:onChange() this.select = ' + this.select); 468 this.eachEvent = this.watcherEvent[this.select]; 469 Logger.info('TextPickerDialog:onChange() this.eachEvent = ' + this.eachEvent); 470 this.myWatcher.startWatcher(this.eachEvent); 471 Logger.info(`onSelect-${this.eachEvent} end`); 472 this.eventArray.push(this.eachEvent); // 新增列表项数据 473 }, 474 }) 475 }) 476 } 477 .width('50%') 478 .align(Alignment.End) 479 } 480 .align(Alignment.Center) 481 .width('70%') 482 .margin({ top: 24, left: 24, right: 24, bottom: 24 }) 483 } 484 .backgroundColor('#f1f3f5') 485 .width('100%') 486 .height(216) 487 } 488 .width('100%') 489 } 490 .width('100%') 491 } 492 .height('100%') 493 } 494 .id('scroller') 495 } 496}