1/* 2* Copyright (C) 2023 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 AVSessionManager from '@ohos.multimedia.avsession'; 17import common from '@ohos.app.ability.common'; 18import control from '../feature/MediaController'; 19import Log from '../common/Logger'; 20 21const TAG: string = 'PresentPage'; 22 23@Entry 24@Component 25struct PresentPage { 26 @State 27 isShowQueue: boolean = false; 28 @StorageLink('isLyric') 29 isLyric: boolean = false; 30 @StorageLink('item') 31 itemShow: Array<AVSessionManager.AVQueueItem> = new Array; 32 @StorageLink('history') 33 history: Array<AVSessionManager.AVSessionDescriptor> = new Array(); 34 @StorageLink('isPlaying') 35 isPlaying: boolean = false; 36 controller = new control(); 37 @StorageLink('metaDataMap') 38 @Watch('onMetaDataChangeCallback') 39 private metaDataMap: Map<string, AVSessionManager.AVMetadata> = new Map(); 40 @StorageLink('playStateMap') 41 private playStateMap: Map<string, AVSessionManager.AVMetadata> = new Map(); 42 @StorageLink('queueTitleMap') 43 private queueTitleMap: Map<string, string> = new Map(); 44 @StorageLink('queueItemsMap') 45 private queueItemsMap: Map<string, Array<AVSessionManager.AVQueueItem>> = new Map(); 46 @StorageLink('lyricMap') 47 private lyricMap: Map<string, string> = new Map(); 48 @StorageLink('bundleNameMap') 49 private bundleNameMap: Map<string, string> = new Map(); 50 @StorageLink('sessionArray') 51 private sessionArray: Array<string> = new Array(); 52 53 async aboutToAppear() { 54 await this.controller.initLink(); 55 await this.controller.startControl(); 56 } 57 58 onMetaDataChangeCallback() { 59 Log.info(TAG, 'metadatachange check metadatamap: ' + JSON.stringify(this.metaDataMap)); 60 Log.info(TAG, 'metadatachange check sessionarray: ' + JSON.stringify(this.sessionArray![0])); 61 } 62 63 build() { 64 Stack() { 65 Image('#00000000') 66 .width('100%') 67 .height('100%') 68 .onTouch((event?: TouchEvent) => { 69 if (event !== undefined && event.type == TouchType.Down) { 70 Log.info(TAG, 'touch down img, terminate self sss'); 71 let context: common.UIAbilityContext | undefined = AppStorage.get<common.UIAbilityContext>('context') 72 context!.terminateSelf() 73 } 74 }) 75 Column() { 76 Stack({ alignContent: Alignment.TopStart }) { 77 Column() { 78 } 79 .width('100%') 80 .height('100%') 81 .backgroundColor('#99ffffff') 82 .zIndex(1) 83 .borderRadius('16vp') 84 .id('FirstPanel') 85 86 Column() { 87 Row() { 88 Image(this.sessionArray[0] && this.metaDataMap.get(this.sessionArray[0]) 89 ? (this.metaDataMap?.get(this.sessionArray[0]))?.mediaImage : $r('app.media.no_music')) 90 .width('48vp') 91 .height('48vp') 92 .id('CurrentImage') 93 Column() { 94 Text(this.sessionArray[0] && this.metaDataMap.get(this.sessionArray[0]) 95 ? (this.metaDataMap?.get(this.sessionArray[0]))?.title : $r('app.string.not_in_play')) 96 .fontSize('16fp') 97 .fontColor('#182431') 98 .maxLines(1) 99 .textOverflow({ overflow: TextOverflow.Ellipsis }) 100 .width('228vp') 101 .id('Title') 102 Text(this.sessionArray[0] && this.metaDataMap.get(this.sessionArray[0]) 103 ? (this.metaDataMap?.get(this.sessionArray[0]))?.artist : $r('app.string.not_in_play')) 104 .fontSize('14fp') 105 .fontColor('#182431') 106 .opacity(0.6) 107 .maxLines(1) 108 .textOverflow({ overflow: TextOverflow.Ellipsis }) 109 .width('228vp') 110 .id('Artist') 111 } 112 .margin({ left: '12vp' }) 113 .alignItems(HorizontalAlign.Start) 114 } 115 .justifyContent(FlexAlign.Start) 116 .width('100%') 117 .margin({ top: '12vp' }) 118 119 Row() { 120 Image(this.isShowQueue ? $r('app.media.list_activate') : $r('app.media.list_none')) 121 .width('24vp') 122 .height('24vp') 123 .id('ShowQueue') 124 .onClick(() => { 125 this.isShowQueue = !this.isShowQueue; 126 Log.info(TAG, 'isShowQueue set to : ' + this.isShowQueue); 127 }) 128 Image($r('app.media.previous')).width('24vp').height('24vp') 129 .id('Previous') 130 .onClick(() => { 131 if (this.sessionArray[0]) { 132 this.controller.previous(this.sessionArray[0]); 133 Log.info(TAG, 'on previous click '); 134 } 135 }) 136 Image(this.isPlaying ? $r('app.media.stopmusic') : $r('app.media.playmusic')) 137 .width('24vp') 138 .height('24vp') 139 .id('PlayOrPause:' + this.isPlaying) 140 .onClick(() => { 141 if (this.sessionArray[0]) { 142 if (this.isPlaying) { 143 this.controller.pause(this.sessionArray[0]); 144 } else { 145 this.controller.play(this.sessionArray[0]); 146 } 147 Log.info(TAG, 'on play/pause click '); 148 } 149 }) 150 Image($r('app.media.next')).width('24vp').height('24vp') 151 .id('Next') 152 .onClick(() => { 153 if (this.sessionArray[0]) { 154 this.controller.next(this.sessionArray[0]); 155 Log.info(TAG, 'on next click '); 156 } 157 }) 158 Image(this.isLyric ? $r('app.media.lyric_activate') : $r('app.media.lyric_none')) 159 .width('24vp') 160 .height('24vp') 161 .id('Lyric') 162 .onClick(() => { 163 this.controller.getLyric(this.sessionArray[0]); 164 Log.info(TAG, ' isLyric set to :' + this.isLyric); 165 }) 166 } 167 .justifyContent(FlexAlign.SpaceBetween) 168 .margin({ left: '12vp', right: '12vp', top: '20vp', bottom: '12vp' }) 169 .width('264vp') 170 .height('24vp') 171 172 Row() { 173 Text(this.sessionArray[0] && this.lyricMap[this.sessionArray[0]] 174 ? this.lyricMap[this.sessionArray[0]] : $r('app.string.not_in_play')) 175 .id('LyricText') 176 .fontColor('#182431') 177 .maxLines(1) 178 .textOverflow({ overflow: TextOverflow.Ellipsis }) 179 } 180 .width('264vp') 181 .height('20vp') 182 .margin({ top: '12vp', bottom: '12vp', left: '12vp', right: '12vp' }) 183 .alignItems(VerticalAlign.Center) 184 .justifyContent(FlexAlign.Center) 185 .visibility(this.isLyric ? Visibility.Visible : Visibility.None) 186 187 Divider() 188 .height('0.5vp') 189 .opacity(0.05) 190 .color('#182431') 191 .width('100%') 192 .margin({ top: '12.5vp' }) 193 .visibility(this.sessionArray.length > 1 ? Visibility.Visible : Visibility.None) 194 Row() { 195 Image(this.sessionArray[1] && this.metaDataMap[this.sessionArray[1]] 196 && this.metaDataMap[this.sessionArray[1]].mediaImage 197 ? (this.metaDataMap[this.sessionArray[1]]).mediaImage : $r('app.media.no_music')) 198 .width('48vp') 199 .height('48vp') 200 .id('HistoryImage') 201 Column() { 202 Text(this.sessionArray[1] && this.metaDataMap[this.sessionArray[1]] 203 ? (this.metaDataMap[this.sessionArray[1]]).title : $r('app.string.not_in_play')) 204 .fontSize('16fp') 205 .maxLines(1) 206 .fontColor('#182431') 207 .id('HistoryTitle') 208 .textOverflow({ overflow: TextOverflow.Ellipsis }) 209 .width('228vp') 210 Text(this.sessionArray[1] && this.bundleNameMap[this.sessionArray[1]] 211 ? (this.bundleNameMap[this.sessionArray[1]]) : '') 212 .fontSize('14fp') 213 .fontColor('#182431') 214 .opacity(0.6) 215 .maxLines(1) 216 .id('HistoryArtist') 217 .textOverflow({ overflow: TextOverflow.Ellipsis }) 218 .width('228vp') 219 } 220 .margin({ left: '12vp' }) 221 .alignItems(HorizontalAlign.Start) 222 .justifyContent(FlexAlign.Center) 223 } 224 .justifyContent(FlexAlign.Start).width('100%').margin({ top: '12vp', bottom: '12.5vp' }) 225 .visibility(this.sessionArray.length > 1 ? Visibility.Visible : Visibility.None) 226 227 Divider() 228 .height('0.5vp') 229 .opacity(0.05) 230 .color('#182431') 231 .width('100%') 232 .visibility(this.sessionArray.length > 2 ? Visibility.Visible : Visibility.None) 233 234 Row() { 235 Image(this.sessionArray[2] && this.metaDataMap?.get(this.sessionArray[2]) 236 && this.metaDataMap?.get(this.sessionArray[2])?.mediaImage 237 ? (this.metaDataMap?.get(this.sessionArray[2]))?.mediaImage : $r('app.media.no_music')) 238 .width('48vp') 239 .height('48vp') 240 Column() { 241 Text(this.sessionArray[2] && this.metaDataMap?.get(this.sessionArray[2]) 242 ? (this.metaDataMap?.get(this.sessionArray[2]))?.title : $r('app.string.not_in_play')) 243 .fontSize('16fp') 244 .fontColor('#182431') 245 .maxLines(1) 246 .textOverflow({ overflow: TextOverflow.Ellipsis }) 247 .width('228vp') 248 Text(this.sessionArray[2] && this.bundleNameMap[this.sessionArray[2]] 249 ? (this.bundleNameMap[this.sessionArray[2]]) : '') 250 .fontSize('14fp') 251 .fontColor('#182431') 252 .opacity(0.6) 253 .maxLines(1) 254 .textOverflow({ overflow: TextOverflow.Ellipsis }) 255 .width('228vp') 256 } 257 .margin({ left: '12vp' }) 258 .alignItems(HorizontalAlign.Start) 259 .justifyContent(FlexAlign.Center) 260 } 261 .justifyContent(FlexAlign.Start) 262 .width('100%') 263 .margin({ top: 10 }) 264 .visibility(this.sessionArray.length > 2 ? Visibility.Visible : Visibility.None) 265 } 266 .width('288vp') 267 .height('100%') 268 .zIndex(2) 269 .margin({ top: '4vp', bottom: '4vp', left: '12vp', right: '12vp' }) 270 } 271 .width('312vp') 272 .height(this.getMediaCardHeight()) 273 .margin({ top: '40vp' }) 274 275 Stack() { 276 Column() { 277 } 278 .width('100%') 279 .height('153vp') 280 .backgroundColor('#99ffffff') 281 .zIndex(1) 282 .borderRadius('24vp') 283 284 Column() { 285 Column() { 286 Text(this.sessionArray[0] 287 && this.queueItemsMap[this.sessionArray[0]] 288 && this.queueItemsMap[this.sessionArray[0]][0] 289 ? this.queueItemsMap[this.sessionArray[0]][0].description.title : 'queue null') 290 .fontSize('16fp') 291 .fontColor('#182431') 292 .maxLines(1) 293 .textOverflow({ overflow: TextOverflow.Ellipsis }) 294 } 295 .alignItems(HorizontalAlign.Start) 296 .height('48vp') 297 .justifyContent(FlexAlign.Center) 298 .width('100%') 299 .id('FirstMusicInQueue') 300 .onClick(() => { 301 if (this.sessionArray[0] && 302 this.queueItemsMap[this.sessionArray[0]] && 303 this.queueItemsMap[this.sessionArray[0]][0] !== undefined) { 304 Log.info(TAG, 'pre skip :' + this.queueItemsMap[this.sessionArray[0]][0].itemId); 305 this.controller.skip(this.sessionArray[0], this.queueItemsMap[this.sessionArray[0]][0].itemId); 306 } 307 }) 308 309 Divider() 310 .height('0.5vp') 311 .opacity(0.05) 312 .color('#182431') 313 .width('100%') 314 315 Column() { 316 Text(this.sessionArray[0] 317 && this.queueItemsMap[this.sessionArray[0]] 318 && this.queueItemsMap[this.sessionArray[0]][1] 319 ? this.queueItemsMap[this.sessionArray[0]][1].description.title : 'queue null') 320 .fontSize('16fp') 321 .fontColor('#182431') 322 .maxLines(1) 323 .textOverflow({ overflow: TextOverflow.Ellipsis }) 324 } 325 .alignItems(HorizontalAlign.Start) 326 .height('48vp') 327 .justifyContent(FlexAlign.Center) 328 .width('100%') 329 .id('SecondMusicInQueue') 330 .onClick(() => { 331 if (this.sessionArray[0] && 332 this.queueItemsMap[this.sessionArray[0]] && 333 this.queueItemsMap[this.sessionArray[0]][1] !== undefined) { 334 Log.info(TAG, 'pre skip :' + this.queueItemsMap[this.sessionArray[0]][1].itemId); 335 this.controller.skip(this.sessionArray[0], this.queueItemsMap[this.sessionArray[0]][1].itemId); 336 } 337 }) 338 339 Divider() 340 .height('0.5vp') 341 .opacity(0.05) 342 .color('#182431') 343 .width('100%') 344 345 Column() { 346 Text(this.sessionArray[0] 347 && this.queueItemsMap[this.sessionArray[0]] 348 && this.queueItemsMap[this.sessionArray[0]][2] 349 ? this.queueItemsMap[this.sessionArray[0]][2].description.title : 'queue null') 350 .fontSize('16fp') 351 .fontColor('#182431') 352 .maxLines(1) 353 .textOverflow({ overflow: TextOverflow.Ellipsis }) 354 } 355 .alignItems(HorizontalAlign.Start) 356 .height('48vp') 357 .justifyContent(FlexAlign.Center) 358 .width('100%') 359 .id('ThirdMusicInQueue') 360 .onClick(() => { 361 if (this.sessionArray[0] && 362 this.queueItemsMap[this.sessionArray[0]] && 363 this.queueItemsMap[this.sessionArray[0]][2] !== undefined) { 364 this.controller.skip(this.sessionArray[0], this.queueItemsMap[this.sessionArray[0]][2].itemId); 365 } 366 }) 367 } 368 .width('288vp') 369 .height('144vp') 370 .id('SecondPanel') 371 .zIndex(2) 372 .alignItems(HorizontalAlign.Start) 373 .margin({ top: '4vp', bottom: '4vp', left: '12vp', right: '12vp' }) 374 } 375 .width('312vp') 376 .height('153vp') 377 .margin({ top: '12vp' }) 378 .visibility(this.isShowQueue ? Visibility.Visible : Visibility.None) 379 } 380 .height(this.getTotalHeight()) 381 .width('312vp') 382 .margin({ top: '40vp', left: '24vp', right: '24vp' }) 383 .backgroundColor('#00000000') 384 } 385 .backgroundImage($r('app.media.background')) 386 .backgroundImageSize(ImageSize.Cover) 387 .alignContent(Alignment.Top) 388 .width('100%') 389 .height('100%') 390 } 391 392 getMediaCardHeight(): string { 393 let mediaNum: number = this.sessionArray.length > 0 ? 394 (this.sessionArray.length > 3 ? 3 : this.sessionArray.length) : 1; // If has 3 or more history, get 3 of them. 395 let mediaExtraHeight: number = ((mediaNum - 1) > 0 ? 12 : 0) + (mediaNum - 1) * 73; // 73 is the length given from UX designer 396 let height: number = 124 + (this.isLyric ? 44 : 0) + mediaExtraHeight; // 124 and 44 is the size given from UX designer 397 Log.info(TAG, 'get height : ' + height); 398 return String(height) + 'vp'; 399 } 400 401 getTotalHeight(): string { 402 let mediaNum: number = this.sessionArray.length > 0 ? 403 (this.sessionArray.length > 3 ? 3 : this.sessionArray.length) : 1; // If has 3 or more history, get 3 of them. 404 let mediaExtraHeight: number = ((mediaNum - 1) > 0 ? 12 : 0) + (mediaNum - 1) * 73; // 73 is the length given from UX designer 405 let height: number = 124 + (this.isLyric ? 44 : 0) + mediaExtraHeight; // 124 and 44 is the length given from UX designer 406 Log.info(TAG, 'get media height : ' + height); 407 height += (this.isShowQueue ? 165 : 0); // 165 is the length given from UX designer 408 Log.info(TAG, 'get total height : ' + height); 409 return String(height + 40) + 'vp'; 410 } 411} 412