1/* 2 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. 3 */ 4import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession' 5import Want from '@ohos.app.ability.Want'; 6import ability from '@ohos.ability.ability'; 7 8import { Logger } from '../../common/util/HiLogger' 9import { createOrGet, globalKeys } from '../../common/global/GlobalThisHelper' 10import { DeviceInfo, DeviceTypes } from '../../common/global/globalmodel/GlobalModel' 11import { LocalAudioFile } from '../../localresource/localaudio/LocalAudioFile' 12import { LocalResourceManager } from '../../localresource/LocalResourceManager'; 13import { AudioPickerViewData } from '../model/AudioPickerViewData'; 14import { AudioPickerViewModel } from '../viewmodel/AudioPickerViewModel'; 15import { AudioPickerPreference } from '../../audiopreference/AudioPickerPreference'; 16import { Constants } from '../../constant/Constants'; 17import { SafetyTipDialog } from '../dialog/SafetyTipDialog'; 18 19const logger: Logger = new Logger('AudioPickerView') 20 21@Component 22export struct AudioPickerView { 23 @StorageLink('navigatorBarHeight') navigatorBarHeight: number = 200 24 @Link isShow: boolean; 25 @State audioPickerData: AudioPickerViewData = new AudioPickerViewData() 26 @State audioPickerViewModel: AudioPickerViewModel = new AudioPickerViewModel() 27 // 选中列表信息 28 @State isSelectedAudioPickerList: Array<LocalAudioFile> = [] 29 @State isSafetyTip: boolean = false 30 @State requestCounts: number = 0 31 @State isSelect: boolean = true 32 @State indexArr: Array<number> = [] 33 // load more 提前的条目数量 34 private loadMoreAdvance: number = 3 35 private pageNo: number = 0; 36 // 设备信息 37 private globalDeviceInfo: DeviceInfo = createOrGet(DeviceInfo, globalKeys.deviceInfo) 38 private audioPickerPreference: AudioPickerPreference = 39 createOrGet(AudioPickerPreference, globalKeys.audioPickerPreference) 40 private localResourceManager: LocalResourceManager = new LocalResourceManager() 41 session: UIExtensionContentSession | undefined 42 want: Want | undefined 43 scroller: Scroller = new Scroller() 44 context: Context = getContext(this) 45 // 弹窗知道了按钮回调 46 dialogKnow: () => void = () => { 47 // 保存安全提示状态 48 this.audioPickerPreference.saveSafetyTipStatus(true) 49 logger.info('isSafetyTip ' + this.isSafetyTip) 50 this.dialogController.close() 51 } 52 dialogController: CustomDialogController = new CustomDialogController({ 53 builder: SafetyTipDialog({ 54 know: this.dialogKnow 55 }), 56 alignment: DialogAlignment.Center 57 }) 58 59 async aboutToAppear() { 60 this.audioPickerData = this.audioPickerViewModel.getDataSource() 61 logger.info('this.audioPickerData.getDataList(): ' + this.audioPickerData.getDataList()) 62 this.isSafetyTip = await this.audioPickerPreference.getSafetyTipStatus() 63 this.audioPickerViewModel.queryAudioPickerList(this.pageNo, this.context) 64 if (!this.isSafetyTip) { 65 this.dialogController.open() 66 } 67 } 68 69 routerBack: () => void = () => { 70 if (this.session !== undefined) { 71 this.session?.sendData({ 'isShowUIExtension': false }) 72 this.session?.terminateSelf() 73 } 74 } 75 76 onBackPress() { 77 this.routerBack() 78 } 79 80 /** 81 * 是否是列表最后一个音频 82 */ 83 isLast(index: number): boolean { 84 this.requestCounts = Constants.PICKER_PAGE_SIZE * (this.pageNo + 1) 85 let musicTotal: number = 0 86 if (this.audioPickerData.totalCount() < this.requestCounts) { 87 musicTotal = this.audioPickerViewModel.getAudioTotal() 88 } 89 if (musicTotal) { 90 return index >= musicTotal - 1 91 } else { 92 return false 93 } 94 } 95 96 /** 97 * 返回赋予临时权限的uri列表回调 98 */ 99 async settingTerminateSelfWithResult() { 100 if (this.session) { 101 let uriArr = await this.localResourceManager.terminateSelfWithResult(this.isSelectedAudioPickerList) 102 logger.info('uriArr length: ' + uriArr.length) 103 let abilityResult: ability.AbilityResult = { 104 resultCode: (uriArr === undefined) ? -1 : 0, 105 want: { 106 parameters: { 107 'ability.params.stream': uriArr, 108 'uriArr': uriArr 109 } 110 } 111 } 112 this.session.terminateSelfWithResult(abilityResult, (err) => { 113 logger.error('terminateSelfWithResult is called: ' + err) 114 }) 115 } else { 116 logger.error(`oncancel session: ${this.session}`) 117 } 118 this.routerBack() 119 } 120 121 build() { 122 if (this.audioPickerViewModel.audioTotal > 0) { 123 Stack({ alignContent: Alignment.TopStart }) { 124 Scroll(this.scroller) { 125 Grid() { 126 LazyForEach(this.audioPickerData, (item: LocalAudioFile, index: number) => { 127 GridItem() { 128 Column() { 129 Row() { 130 Image(item.getThumbnail) 131 .width(48) 132 .height(48) 133 .margin({ right: 16 }) 134 .borderRadius(8) 135 .draggable(false) 136 .id('audiopicker_thumbnail') 137 138 Column() { 139 Text(item.name) 140 .fontSize(16) 141 .fontColor($r('sys.color.ohos_id_color_text_primary')) 142 .fontWeight(FontWeight.Medium) 143 .lineHeight(21) 144 .width('100%') 145 .height(21) 146 .maxLines(1) 147 .textOverflow({ overflow: TextOverflow.Ellipsis }) 148 .margin({ bottom: 2 }) 149 .id('audiopicker_name') 150 151 Text() { 152 if (item.artist && item.album) { 153 Span(item.artist) 154 Span('-') 155 Span(item.album) 156 } else if (item.artist || item.album) { 157 Span(item.artist || item.album) 158 } else { 159 Span('') 160 } 161 } 162 .fontSize(12) 163 .fontWeight(FontWeight.Regular) 164 .fontColor($r('sys.color.ohos_id_color_text_tertiary')) 165 .lineHeight(16) 166 .maxLines(1) 167 .width('100%') 168 .height(16) 169 .textOverflow({ overflow: TextOverflow.Ellipsis }) 170 .textAlign(TextAlign.Start) 171 .id('audiopicker_artist_album') 172 } 173 .width('calc(100% - 128vp)') 174 .alignItems(HorizontalAlign.Start) 175 .justifyContent(FlexAlign.Start) 176 .margin({ right: 40 }) 177 178 Column() { 179 Checkbox() 180 .selectedColor($r('sys.color.ohos_id_color_component_activated')) 181 .shape(CheckBoxShape.CIRCLE) 182 .onChange((value) => { 183 if (value) { 184 this.isSelectedAudioPickerList.push(item) 185 this.indexArr.push(index) 186 } else { 187 this.isSelectedAudioPickerList = this.isSelectedAudioPickerList.filter(val => val != item) 188 let selectIndex = this.indexArr.indexOf(index) 189 if(selectIndex != -1){ 190 this.indexArr.splice(selectIndex, 1) 191 } 192 } 193 let keyPickNum = this.want?.parameters?.key_pick_num 194 logger.info('key_pick_num: ' + JSON.stringify(keyPickNum)) 195 if (keyPickNum) { 196 if (this.isSelectedAudioPickerList.length < keyPickNum) { 197 this.isSelect = true 198 } else { 199 this.isSelect = false 200 } 201 } 202 logger.info('indexArr: ' + JSON.stringify(this.indexArr)) 203 logger.info('isSelect: ' + this.isSelect) 204 }) 205 .enabled(this.indexArr.indexOf(index) != -1 ? true : this.isSelect) 206 .unselectedColor($r('sys.color.ohos_id_color_switch_outline_off')) 207 .width(20) 208 .height(20) 209 } 210 .width(24) 211 .height(24) 212 } 213 .width('100%') 214 .height(72) 215 .alignItems(VerticalAlign.Center) 216 .justifyContent(FlexAlign.SpaceBetween) 217 218 if (!this.isLast(index)) { 219 Divider() 220 .strokeWidth('1px') 221 .margin({ left: 64 }) 222 .backgroundColor($r('sys.color.ohos_id_color_list_separator')) 223 } 224 } 225 .padding({ left: 16, right: 16 }) 226 } 227 }, (item: LocalAudioFile) => { 228 return item.uri 229 }) 230 } 231 .onScrollIndex((start, end) => { 232 // 判断是否还有更多数据 233 if (this.audioPickerData.totalCount() < this.requestCounts) { 234 logger.warn(`audioPickerData less than ,size: ${this.audioPickerData.totalCount()}`) 235 this.audioPickerData.hasMoreData = false 236 return 237 } else { 238 this.audioPickerData.hasMoreData = true 239 } 240 // 判断首页数据是否满足一页 241 if (this.audioPickerData) { 242 if (this.audioPickerData.totalCount() < Constants.PICKER_PAGE_SIZE && 243 this.pageNo === Constants.PAGE_COUNT) { 244 logger.warn('audioPickerData less than 100,size: ' + this.audioPickerData.totalCount()) 245 return 246 } 247 } 248 // 判断是否是在加载中 249 if (this.audioPickerData.isLoadMore || !this.audioPickerData.hasMoreData) { 250 logger.warn('audioPickerData is showing more view : ' + this.audioPickerData.isLoadMore + 251 ' no more data: ' + this.audioPickerData.hasMoreData) 252 return 253 } 254 // 查询下一页数据 255 let lastIndex: number = this.audioPickerData.totalCount() - 1 256 if (end >= lastIndex - this.loadMoreAdvance) { 257 this.audioPickerData.hasMoreData = true 258 this.audioPickerViewModel.loadMore(this.pageNo, this.context).then((res) => { 259 if (res) { 260 // 加载成功后,页面+1 261 this.pageNo++ 262 logger.info(`get success pageNo:${this.pageNo}`) 263 } 264 }) 265 } 266 }) 267 } 268 .scrollBar(BarState.Off) 269 // 手机端列表高度要 - 标题 - 已选完成栏 - 提示语栏目 - 底部避让,其他设备不涉及底部避让 270 .margin({ bottom: this.globalDeviceInfo.deviceType === DeviceTypes.PHONE ? 108 : 96 }) 271 272 Column() { 273 Row() { 274 Text() { 275 Span($r('app.string.is_elected')) 276 Span(`(${this.isSelectedAudioPickerList.length})`) 277 } 278 .fontSize(16) 279 .fontColor($r('sys.color.ohos_id_color_text_primary')) 280 .fontWeight(FontWeight.Medium) 281 .height(22) 282 .id('audiopicker_selected') 283 284 Button($r('app.string.complete'), { type: ButtonType.Capsule, stateEffect: false }) 285 .fontColor($r('sys.color.ohos_id_color_text_primary_contrary')) 286 .backgroundColor($r('sys.color.ohos_id_color_component_activated')) 287 .opacity(this.isSelectedAudioPickerList.length ? 1 : 0.4) 288 .width(72) 289 .height(28) 290 .onClick(() => { 291 if (this.isSelectedAudioPickerList.length > 0) { 292 this.settingTerminateSelfWithResult() 293 this.isShow = false 294 } else { 295 this.isShow = true 296 } 297 }) 298 .id('audiopicker_button') 299 } 300 .width('100%') 301 .height(52) 302 .padding({ left: 16, right: 16 }) 303 .alignItems(VerticalAlign.Center) 304 .justifyContent(FlexAlign.SpaceBetween) 305 306 Row() { 307 Image($r('app.media.ic_public_privacy')) 308 .width(14) 309 .height(14) 310 Text($r('app.string.only_selected_items_can_be_accessed')) 311 .fontSize(12) 312 .fontColor($r('sys.color.ohos_id_color_tertiary')) 313 .width(96) 314 .height(16) 315 } 316 .width(114) 317 .height(28) 318 .justifyContent(FlexAlign.SpaceBetween) 319 } 320 .position({ x: 0, y: 576 }) 321 .height(this.globalDeviceInfo.deviceType === DeviceTypes.PHONE ? 108 : 96) 322 .padding(this.globalDeviceInfo.deviceType === DeviceTypes.PHONE ? 323 { bottom: `${this.navigatorBarHeight}px` } : { bottom: 0 }) 324 } 325 .width(this.globalDeviceInfo.deviceType === DeviceTypes.PHONE ? '100%' : 480) 326 .height(this.globalDeviceInfo.deviceType === DeviceTypes.PHONE ? 684 : 560) 327 } else { 328 Column() { 329 Image($r('app.media.emptypage')) 330 .width(96) 331 .height(96) 332 .margin({ bottom: 8 }) 333 334 Text($r('app.string.no_matching_content')) 335 .fontSize(14) 336 .fontColor($r('sys.color.ohos_id_color_text_tertiary')) 337 .fontFamily('HarmonyHeiTi') 338 .fontWeight(FontWeight.Regular) 339 .lineHeight(19) 340 } 341 .width(this.globalDeviceInfo.deviceType === DeviceTypes.PHONE ? '100%' : 480) 342 .height(this.globalDeviceInfo.deviceType === DeviceTypes.PHONE ? 411 : 560) 343 .justifyContent(FlexAlign.Center) 344 .alignItems(HorizontalAlign.Center) 345 } 346 } 347}