1/* 2 * Copyright (c) 2021 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 worker from '@ohos.worker' 17import { FirstLevelByType } from './FirstLevelByType' 18import { SecondLevelByFold } from './SecondLevelByFold' 19import { ThirdLevelHasDetail } from '../pages/ThirdLevelHasDetail' 20import { ThirdLevelHasPic } from '../pages/ThirdLevelHasPic' 21import { 22 MenuLevel, 23 TerminateReason, 24 MediaType, 25 MediaName 26} from '../../../../../../common/src/main/ets/components/Data/Constants' 27import { FileInfo } from '../../../../../../common/src/main/ets/components/Data/FileInfo' 28import { TopPathInfo } from '../../../../../../common/src/main/ets/components/Data/TopPathInfo' 29import { terminateSelfWithResult } from '../../../../../../common/src/main/ets/components/Utils/AbilityUtils' 30import { getFirstMenu } from '../../../../../../common/src/main/ets/components/Utils/FileManagerServiceUtils' 31import { logInfo, logDebug, logError } from '../../../../../../common/src/main/ets/components/Utils/LogUtils' 32import { changeStringToType, updateTopPathInfo } from '../../../../../../common/src/main/ets/components/Utils/Utils' 33import { WarningDialog } from '../../../../../../common/src/main/ets/components/View/WarningDialog' 34 35@Entry 36@Component 37struct allIndex { 38 private TAG: string = 'Main' 39 40 build() { 41 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.End, justifyContent: FlexAlign.SpaceBetween }) { 42 Stack({ alignContent: Alignment.Bottom }) { 43 Column() { 44 } 45 .onClick(() => { 46 globalThis.context.terminateSelf((err, data) => { 47 logInfo(this.TAG, 'terminateSelf success') 48 }) 49 }) 50 .width('100%') 51 .height('100%') 52 53 Index() 54 } 55 .width('100%') 56 .height('100%') 57 } 58 .backgroundColor('rgba(0,0,0,0.1)') 59 .position({ x: 0, y: 0 }) 60 .width('100%') 61 .height('100%') 62 } 63} 64 65@Component 66struct Index { 67 private TAG: string = 'Main' 68 private mWorker 69 private customDialogController: CustomDialogController = new CustomDialogController({ 70 builder: WarningDialog({ code: $code }) 71 }) 72 @State mFirstMenuData: FileInfo[] = [] 73 @State mSecondMenuData: FileInfo[] = [] 74 @State mThirdMenuPicData: FileInfo[] = [] 75 @State mThirdMenuDetailData: FileInfo[] = [] 76 @State mType: string = '' 77 @State mMenuLevel: number = MenuLevel.MENU_FIRST_LEVEL_BY_TYPE 78 @State mCurrentPath: string = '' 79 @State code: number = 2; 80 @StorageLink('startMode') mCurrentMode: string = 'choose' 81 @StorageLink('topPathInfo') topPathInfo: Array<TopPathInfo> = updateTopPathInfo([], '文件类型', '') 82 scroller: Scroller = new Scroller() 83 84 aboutToAppear() { 85 if (globalThis.debugMode) { 86 this.mFirstMenuData = getFirstMenu('') 87 logDebug(this.TAG, 'mFirstMenuData length = ' + this.mFirstMenuData.length) 88 } else { 89 logInfo(this.TAG, 'aboutToAppear') 90 this.initWork() 91 logInfo(this.TAG, 'send message to worker') 92 this.mWorker.postMessage({ 93 request_data: 'getRoot', 94 device_name: 'local', 95 menu_level: this.mMenuLevel, 96 MediaType: this.mType, 97 path: this.mCurrentPath, 98 context: globalThis.context, 99 }) 100 } 101 } 102 103 private initWork() { 104 if (this.mWorker == undefined) { 105 logInfo(this.TAG, 'initWorker') 106 this.mWorker = new worker.Worker('RK/ets/workers/DataWorker.js', { type: 'classic', name: 'filePicker' }) 107 this.mWorker.onerror = this.onError.bind(this) 108 this.mWorker.onmessageerror = this.onMessageError.bind(this) 109 this.mWorker.onexit = this.onExit.bind(this) 110 this.mWorker.onmessage = this.onMessage.bind(this) 111 } 112 } 113 114 private onError(e): void{ 115 logError(this.TAG, 'onError = ' + JSON.stringify(e)) 116 } 117 118 private onMessageError(e): void{ 119 logError(this.TAG, 'onMessageError = ' + JSON.stringify(e)) 120 } 121 122 private onExit(): void{ 123 logInfo(this.TAG, 'onExit') 124 this.mWorker = undefined 125 } 126 127 private onMessage(result) { 128 logInfo(this.TAG, 'main thread onMessage'); 129 var params = result.data.params; 130 if (params.save_name && params.retCode == -17) { 131 logInfo(this.TAG, 'main thread onMessage pop-up window'); 132 AlertDialog.show( 133 { 134 title: '文件已存在', 135 message: '是否覆盖原文件?', 136 primaryButton: { 137 value: '取消', 138 action: () => { 139 } 140 }, 141 secondaryButton: { 142 value: '确定', 143 action: () => { 144 logInfo(this.TAG, 'main thread onMessage confirm and conver file'); 145 this.mWorker.postMessage({ 146 request_data: 'coverFile', 147 device_name: 'local', 148 MediaType: this.mType, 149 path: this.mCurrentPath, 150 cover_name: params.save_name, 151 context: globalThis.context, 152 }) 153 } 154 }, 155 cancel: () => { 156 } 157 } 158 ) 159 return 160 } 161 var file = JSON.parse(String.fromCharCode.apply(null, new Uint16Array(result.data.data))); 162 if (params.request_data == 'createFile' || params.request_data == 'coverFile') { 163 if (file.code == undefined) { 164 terminateSelfWithResult(TerminateReason.SUCCESS, file) 165 } else { 166 if (params.path == 'datashare:///media/root') { 167 this.code = 2; 168 this.customDialogController.open() 169 } else { 170 this.code = file.code 171 this.customDialogController.open() 172 } 173 } 174 return 175 } 176 if (Array.isArray(file)) { 177 let listData: Array<FileInfo> = [] 178 for (var index = 0;index < file.length; index++) { 179 var info = file[index] 180 let item = new FileInfo(info.name) 181 item.path = info.path 182 item.type = info.type 183 item.size = info.size 184 item.addedTime = info.added_time 185 item.modifiedTime = info.modified_time 186 if (params.menu_level == MenuLevel.MENU_FIRST_LEVEL_BY_TYPE) { 187 if (item.name == 'MEDIA_TYPE_IMAGE') { 188 item.name = '图片' 189 item.mediaType = 'image' 190 item.thumbnail = $r("app.media.ic_type_image") 191 } else if (item.name == 'MEDIA_TYPE_VIDEO') { 192 item.name = '视频' 193 item.mediaType = 'video' 194 item.thumbnail = $r("app.media.ic_type_video") 195 } else if (item.name == 'MEDIA_TYPE_AUDIO') { 196 item.name = '音乐' 197 item.mediaType = 'audio' 198 item.thumbnail = $r("app.media.ic_type_audio") 199 } else if (item.name == 'MEDIA_TYPE_FILE') { 200 item.name = '文档' 201 item.mediaType = 'file' 202 item.thumbnail = $r("app.media.ic_type_file") 203 } 204 } 205 206 if (params.menu_level == MenuLevel.MENU_THIRD_LEVEL_HAS_DETAIL) { 207 if (this.mCurrentMode == 'save' && item.type != MediaType.MEDIA_TYPE_ALBUM) { 208 break 209 } 210 } 211 listData.push(item) 212 } 213 logInfo(this.TAG, 'onMessage menu_level = ' + params.menu_level + ' request_data = ' + params.request_data) 214 if (params.menu_level == MenuLevel.MENU_FIRST_LEVEL_BY_TYPE && params.request_data == 'getRoot') { 215 logInfo(this.TAG, 'mFirstMenuData length = ' + listData.length) 216 this.mFirstMenuData = listData 217 } else if (params.menu_level == MenuLevel.MENU_SECOND_LEVEL_BY_FOLD) { 218 logInfo(this.TAG, 'mSecondMenuData length = ' + listData.length) 219 this.mSecondMenuData = listData 220 } else if (params.menu_level == MenuLevel.MENU_THIRD_LEVEL_HAS_PIC) { 221 logInfo(this.TAG, 'mThirdMenuPicData length = ' + listData.length) 222 this.mThirdMenuPicData = listData 223 } else if (params.menu_level == MenuLevel.MENU_THIRD_LEVEL_HAS_DETAIL) { 224 logInfo(this.TAG, 'mThirdMenuDetailData length = ' + listData.length) 225 if (listData.length > 0) { 226 this.mThirdMenuDetailData = listData 227 } else { 228 this.mThirdMenuDetailData = [] 229 } 230 } 231 } 232 } 233 234 build() { 235 Column() { 236 TopBarArea() 237 238 Column() { 239 Column() { 240 Row() { 241 List() { 242 ForEach(this.topPathInfo, (item: TopPathInfo) => { 243 ListItem() { 244 Row() { 245 if (item.name != '文件类型') { 246 Image($r("app.media.ic_public_right")) 247 .width(12 * 1.3) 248 .height(24 * 1.3) 249 .margin({ 250 left: 4 * 1.3, 251 right: 4 * 1.3 252 }) 253 } 254 255 Text(item.name) 256 .height(24 * 1.3) 257 .fontColor('#000000') 258 .fontSize(16 * 1.3) 259 .fontWeight(FontWeight.Medium) 260 .opacity(item.opacity) 261 .onClick(() => { 262 logInfo(this.TAG, item.name + ' onClick') 263 if (item.name == '文件类型') { 264 updateTopPathInfo([], '文件类型', '') 265 this.mMenuLevel = MenuLevel.MENU_FIRST_LEVEL_BY_TYPE 266 this.mType = '' 267 } else if (this.mMenuLevel == MenuLevel.MENU_THIRD_LEVEL_HAS_PIC || (this.mMenuLevel == MenuLevel.MENU_THIRD_LEVEL_HAS_DETAIL)) { 268 this.topPathInfo.pop() 269 this.topPathInfo[this.topPathInfo.length - 1].opacity = 1 270 if (this.topPathInfo.length > 1) { 271 var index = this.topPathInfo.length - 1 272 this.mCurrentPath = this.topPathInfo[index].path 273 this.mMenuLevel = MenuLevel.MENU_SECOND_LEVEL_BY_FOLD 274 } else { 275 this.mMenuLevel = MenuLevel.MENU_FIRST_LEVEL_BY_TYPE 276 this.mType = '' 277 } 278 } 279 }) 280 } 281 } 282 }, item => item.name.toString()) 283 } 284 .padding({ right: 24 * 1.3 }) 285 .listDirection(Axis.Horizontal) 286 } 287 .alignItems(VerticalAlign.Center) 288 .width('100%') 289 .height(48 * 1.3) 290 .margin({ left: 12 * 1.3, top: 4 * 1.3 }) 291 .padding({ top: 13 * 1.3, bottom: 13 * 1.3 }) 292 293 Scroll(this.scroller) { 294 Column() { 295 if (this.mMenuLevel == MenuLevel.MENU_FIRST_LEVEL_BY_TYPE) { 296 FirstLevelByType({ 297 mFileList: this.mFirstMenuData, 298 mType: $mType, 299 mMenuLevel: $mMenuLevel, 300 mCurrentPath: $mCurrentPath, 301 mWorker: this.mWorker, 302 }) 303 } else if (this.mMenuLevel == MenuLevel.MENU_SECOND_LEVEL_BY_FOLD) { 304 SecondLevelByFold({ 305 mType: $mType, 306 mMenuLevel: $mMenuLevel, 307 mCurrentPath: $mCurrentPath, 308 mWorker: this.mWorker, 309 mFileList: $mSecondMenuData 310 }) 311 } else if (this.mMenuLevel == MenuLevel.MENU_THIRD_LEVEL_HAS_PIC) { 312 ThirdLevelHasPic({ 313 mType: $mType, 314 mMenuLevel: $mMenuLevel, 315 mCurrentPath: $mCurrentPath, 316 mWorker: this.mWorker, 317 mFileList: $mThirdMenuPicData 318 }) 319 } else if (this.mMenuLevel == MenuLevel.MENU_THIRD_LEVEL_HAS_DETAIL) { 320 ThirdLevelHasDetail({ 321 mType: $mType, 322 mMenuLevel: $mMenuLevel, 323 mCurrentPath: $mCurrentPath, 324 mWorker: this.mWorker, 325 mFileInfo: $mThirdMenuDetailData 326 }) 327 } 328 Row() { 329 }.width('100%').height(53 * 1.3) 330 } 331 .alignItems(HorizontalAlign.Start) 332 } 333 .scrollBar(BarState.Off) 334 .scrollable(ScrollDirection.Vertical) 335 } 336 .alignItems(HorizontalAlign.Start) 337 } 338 .alignItems(HorizontalAlign.Start) 339 .height(globalThis.mainDialogHeight - 140 * 1.3) 340 341 BottomBar({ 342 mCurrentPath: $mCurrentPath, 343 mMenuLevel: $mMenuLevel, 344 mType: $mType, 345 mWorker: this.mWorker 346 }) 347 } 348 .padding({ left: 12 * 1.3, right: 12 * 1.3 }) 349 .width('100%') 350 .height(globalThis.mainDialogHeight) 351 .border({ radius: 24 }) 352 .backgroundColor('#F1F3F5') 353 } 354} 355 356@Component 357struct TopBarArea { 358 build() { 359 Row() { 360 Text('文件类型') 361 .width(98 * 1.3) 362 .height(33 * 1.3) 363 .fontSize(24 * 1.3) 364 .fontColor('#182431') 365 .fontWeight(FontWeight.Medium) 366 .margin({ left: 12 * 1.3 }) 367 } 368 .height(64 * 1.3) 369 .width('100%') 370 .border({ radius: 24 }) 371 .padding({ top: 8 * 1.3 }) 372 } 373} 374 375@Component 376struct BottomBar { 377 private TAG: string = 'BottomBar' 378 private mWorker 379 @State currentChoseFiles: Array<string> = [] 380 @Link mType: string 381 @Link mMenuLevel: number 382 @Link mCurrentPath: string 383 @StorageLink('choseFiles') @Watch('choseFileChange') choseFiles: Array<FileInfo> = [] 384 385 aboutToAppear() { 386 logInfo(this.TAG, 'current choose file number = ' + this.currentChoseFiles.length) 387 } 388 389 private choseFileChange() { 390 this.currentChoseFiles = [] 391 let files: Array<FileInfo> = AppStorage.Get('choseFiles') 392 files.forEach((item: FileInfo) => { 393 this.currentChoseFiles.push(item.name) 394 }) 395 logInfo(this.TAG, 'current choose file number = ' + this.currentChoseFiles.length) 396 } 397 398 build() { 399 Row() { 400 Button() { 401 Text('取消') 402 .width(110 * 1.3) 403 .height(22 * 1.3) 404 .fontSize(16 * 1.3) 405 .fontWeight(FontWeight.Medium) 406 .fontColor('#007DFF') 407 .textAlign(TextAlign.Center) 408 } 409 .width(150 * 1.3) 410 .height(40 * 1.3) 411 .margin({ left: 12 * 1.3, top: 12 * 1.3, bottom: 24 * 1.3 }) 412 .backgroundColor('#E5E8EA') 413 .onClick((event: ClickEvent) => { 414 terminateSelfWithResult(TerminateReason.NO_ACTION, '') 415 AppStorage.Set('choseFiles', []) 416 }) 417 418 if (globalThis.startMode == 'save') { 419 Button() { 420 Text($r("app.string.btn_save")) 421 .width(110 * 1.3) 422 .height(22 * 1.3) 423 .fontSize(16 * 1.3) 424 .fontWeight(FontWeight.Medium) 425 .fontColor('#007DFF') 426 .textAlign(TextAlign.Center) 427 .opacity(this.mMenuLevel != MenuLevel.MENU_FIRST_LEVEL_BY_TYPE ? 1 : 0.4) 428 } 429 .backgroundColor(this.mMenuLevel != MenuLevel.MENU_FIRST_LEVEL_BY_TYPE ? '#E5E8EA' : '#ECEEF0') 430 .margin({ 431 left: 12 * 1.3, 432 top: 12 * 1.3, 433 bottom: 24 * 1.3 434 }) 435 .height(40 * 1.3) 436 .width(150 * 1.3) 437 .stateEffect(this.mMenuLevel == MenuLevel.MENU_FIRST_LEVEL_BY_TYPE ? false : true) 438 .onClick((event: ClickEvent) => { 439 this.mWorker.postMessage({ 440 request_data: 'createFile', 441 device_name: 'local', 442 menu_level: this.mMenuLevel, 443 MediaType: this.mType, 444 path: this.mCurrentPath, 445 save_name: globalThis.saveFile, 446 context: globalThis.context, 447 }) 448 }) 449 } else { 450 Button() { 451 Text($r("app.string.btn_upload")) 452 .width(110 * 1.3) 453 .height(22 * 1.3) 454 .fontSize(16 * 1.3) 455 .fontWeight(FontWeight.Medium) 456 .fontColor('#007DFF') 457 .textAlign(TextAlign.Center) 458 .opacity(this.choseFiles.length != 0 ? 1 : 0.4) 459 } 460 .backgroundColor(this.choseFiles.length != 0 ? '#E5E8EA' : '#ECEEF0') 461 .stateEffect(this.choseFiles.length != 0) 462 .margin({ 463 left: 12 * 1.3, 464 top: 12 * 1.3, 465 bottom: 24 * 1.3 466 }) 467 .height(40 * 1.3) 468 .width(150 * 1.3) 469 .onClick(() => { 470 let result: string = '' 471 this.choseFiles.forEach((item: FileInfo) => { 472 result += item.path + ';' 473 }) 474 terminateSelfWithResult(TerminateReason.SUCCESS, result) 475 AppStorage.Set('choseFiles', []) 476 }) 477 } 478 } 479 .height(76 * 1.3) 480 .width('100%') 481 .backgroundColor('#F1F3F5') 482 } 483}