王士厅

音频悬浮窗

@@ -31,6 +31,14 @@ export enum EmitterEventId { @@ -31,6 +31,14 @@ export enum EmitterEventId {
31 // App进入后台 31 // App进入后台
32 APP_ENTER_BACKGROUD = 101, 32 APP_ENTER_BACKGROUD = 101,
33 33
  34 + // 更换音频名称
  35 + AUDIO_CHANGE_TITLe = 10,
  36 +
  37 + // 更换音频状态
  38 + AUDIO_CHANGE_STATUS = 11,
  39 +
  40 + // 获取音频悬浮窗焦点状态
  41 + AUDIO_WINDOW_TYPE = 12,
34 42
35 } 43 }
36 44
@@ -23,7 +23,7 @@ export class EmitterUtils { @@ -23,7 +23,7 @@ export class EmitterUtils {
23 * @param eventId 事件id 23 * @param eventId 事件id
24 * @param str 字符串数据 24 * @param str 字符串数据
25 */ 25 */
26 - static sendEvent(eventId: number, str?: string) { 26 + static sendEvent(eventId: number, str?: string | number) {
27 let event: emitter.InnerEvent = { 27 let event: emitter.InnerEvent = {
28 eventId: eventId, 28 eventId: eventId,
29 priority: emitter.EventPriority.LOW 29 priority: emitter.EventPriority.LOW
@@ -142,6 +142,7 @@ export struct MorningEveningPaperComponent { @@ -142,6 +142,7 @@ export struct MorningEveningPaperComponent {
142 if (this.compListItem.operDataList && this.compListItem.operDataList.length > 0) { 142 if (this.compListItem.operDataList && this.compListItem.operDataList.length > 0) {
143 this.getAllContentInteractData(this.compListItem.operDataList) 143 this.getAllContentInteractData(this.compListItem.operDataList)
144 } 144 }
  145 + Logger.debug('compInfoBean?.compList[0].audioDataList', JSON.stringify(compInfoBean?.compList[0].audioDataList))
145 if (compInfoBean?.compList[0].audioDataList) { 146 if (compInfoBean?.compList[0].audioDataList) {
146 this.audioPlayUrl = compInfoBean?.compList[0].audioDataList[0].audioUrl 147 this.audioPlayUrl = compInfoBean?.compList[0].audioDataList[0].audioUrl
147 this.audioTitle = compInfoBean?.compList[0].audioDataList[0].title 148 this.audioTitle = compInfoBean?.compList[0].audioDataList[0].title
@@ -301,8 +302,9 @@ export struct MorningEveningPaperComponent { @@ -301,8 +302,9 @@ export struct MorningEveningPaperComponent {
301 .onClick(() => { 302 .onClick(() => {
302 Logger.info("TAG", "cj compInfoBean onClick1 = " + this.isAudioPlaying) 303 Logger.info("TAG", "cj compInfoBean onClick1 = " + this.isAudioPlaying)
303 // dialog.open() 304 // dialog.open()
304 - this.AudioSuspension.showWindow()  
305 - // this.playerController.firstPlay(this.audioPlayUrl) 305 + // this.playerController.firstPlay(this.audioPlayUrl, this.audioTitle)
  306 + this.AudioSuspension.setPlayerUrl(this.audioPlayUrl, this.audioTitle)
  307 + Logger.info(TAG, "this.audioPlayUrl = " + this.audioPlayUrl)
306 Logger.info("TAG", "cj compInfoBean onClick2 = " + this.isAudioPlaying) 308 Logger.info("TAG", "cj compInfoBean onClick2 = " + this.isAudioPlaying)
307 }) 309 })
308 } 310 }
@@ -23,6 +23,9 @@ import { WDRouterPage, WDRouterRule } from 'wdRouter/Index'; @@ -23,6 +23,9 @@ import { WDRouterPage, WDRouterRule } from 'wdRouter/Index';
23 import { PageRepository } from '../../repository/PageRepository'; 23 import { PageRepository } from '../../repository/PageRepository';
24 import { SpConstants } from 'wdConstant/Index'; 24 import { SpConstants } from 'wdConstant/Index';
25 import { WDShare } from 'wdShare/Index'; 25 import { WDShare } from 'wdShare/Index';
  26 +import { AudioSuspensionModel } from '../../viewmodel/AudioSuspensionModel'
  27 +import { EmitterEventId, EmitterUtils } from 'wdKit/Index'
  28 +import { PlayerConstants } from 'wdPlayer'
26 29
27 const TAG = 'OperRowListView'; 30 const TAG = 'OperRowListView';
28 31
@@ -55,15 +58,23 @@ export struct OperRowListView { @@ -55,15 +58,23 @@ export struct OperRowListView {
55 @State newsStatusOfUser: batchLikeAndCollectResult | undefined = undefined // 点赞、收藏状态 58 @State newsStatusOfUser: batchLikeAndCollectResult | undefined = undefined // 点赞、收藏状态
56 @State likeBean: Record<string, string> = {} 59 @State likeBean: Record<string, string> = {}
57 @State audioUrl: string = '' 60 @State audioUrl: string = ''
  61 + @State audioTitle: string = ''
58 @State bgColor: ResourceColor = Color.White 62 @State bgColor: ResourceColor = Color.White
59 @State showCommentIcon: boolean = true 63 @State showCommentIcon: boolean = true
60 @State bottomSafeHeight: number = AppStorage.get<number>('bottomSafeHeight') || 0 64 @State bottomSafeHeight: number = AppStorage.get<number>('bottomSafeHeight') || 0
61 needLike: boolean = true 65 needLike: boolean = true
  66 + private AudioSuspension = new AudioSuspensionModel()
  67 + @State currentStatus: number | string | undefined = 0;
62 68
63 async aboutToAppear() { 69 async aboutToAppear() {
64 console.info(TAG, '22222----', this.styleType) 70 console.info(TAG, '22222----', this.styleType)
65 console.info(TAG, '3333----', this.needLike) 71 console.info(TAG, '3333----', this.needLike)
66 this.handleStyle() 72 this.handleStyle()
  73 + EmitterUtils.receiveEvent(EmitterEventId.AUDIO_CHANGE_STATUS, (val: number | string | undefined) => {
  74 + console.log(TAG,'this.currentStatus', val)
  75 + this.currentStatus = val
  76 + })
  77 +
67 } 78 }
68 79
69 async onDetailUpdated() { 80 async onDetailUpdated() {
@@ -97,7 +108,9 @@ export struct OperRowListView { @@ -97,7 +108,9 @@ export struct OperRowListView {
97 // 音频需要数据 108 // 音频需要数据
98 if (this.operationButtonList?.includes('listen')) { 109 if (this.operationButtonList?.includes('listen')) {
99 this.audioUrl = this.contentDetailData.audioList[0]?.audioUrl || '' 110 this.audioUrl = this.contentDetailData.audioList[0]?.audioUrl || ''
  111 + this.audioTitle = this.contentDetailData.newsTitle || ''
100 console.log(TAG, 'this.audioUrl+++', this.audioUrl) 112 console.log(TAG, 'this.audioUrl+++', this.audioUrl)
  113 + console.log(TAG, 'this.audioTitle+++', this.audioTitle)
101 } 114 }
102 } 115 }
103 116
@@ -231,13 +244,14 @@ export struct OperRowListView { @@ -231,13 +244,14 @@ export struct OperRowListView {
231 @Builder 244 @Builder
232 builderListen() { 245 builderListen() {
233 Column() { 246 Column() {
234 - Image($r('app.media.icon_listen')) 247 + Image(this.currentStatus === PlayerConstants.STATUS_START ? $r("app.media.icon_audio_pause") : $r("app.media.icon_listen"))
235 .width(24) 248 .width(24)
236 .height(24) 249 .height(24)
237 .aspectRatio(1) 250 .aspectRatio(1)
238 .interpolation(ImageInterpolation.High) 251 .interpolation(ImageInterpolation.High)
239 .onClick((event: ClickEvent) => { 252 .onClick((event: ClickEvent) => {
240 - ToastUtils.showToast('音频为公共方法,待开发', 1000); 253 + this.AudioSuspension.setPlayerUrl(this.audioUrl, this.audioTitle)
  254 + // ToastUtils.showToast('音频为公共方法,待开发', 1000);
241 }) 255 })
242 } 256 }
243 .width(42) 257 .width(42)
@@ -2,6 +2,7 @@ import window from '@ohos.window'; @@ -2,6 +2,7 @@ import window from '@ohos.window';
2 import { Logger } from 'wdKit'; 2 import { Logger } from 'wdKit';
3 import { WDPlayerController } from 'wdPlayer'; 3 import { WDPlayerController } from 'wdPlayer';
4 import { BusinessError } from '@ohos.base'; 4 import { BusinessError } from '@ohos.base';
  5 +import { EmitterEventId, EmitterUtils } from 'wdKit/Index'
5 6
6 const TAG = 'AudioSuspensionModel' 7 const TAG = 'AudioSuspensionModel'
7 8
@@ -11,6 +12,10 @@ const TAG = 'AudioSuspensionModel' @@ -11,6 +12,10 @@ const TAG = 'AudioSuspensionModel'
11 export class AudioSuspensionModel { 12 export class AudioSuspensionModel {
12 public playerController: SubscribedAbstractProperty<WDPlayerController> = AppStorage.link<WDPlayerController>('playerController') 13 public playerController: SubscribedAbstractProperty<WDPlayerController> = AppStorage.link<WDPlayerController>('playerController')
13 public floatWindowClass: SubscribedAbstractProperty<window.Window> = AppStorage.link<window.Window>('floatWindowClass') 14 public floatWindowClass: SubscribedAbstractProperty<window.Window> = AppStorage.link<window.Window>('floatWindowClass')
  15 + public srcTitle: string = ''
  16 + private url: string = ''
  17 + private expandWidth: number = 800
  18 + private expandHeight: number = 200
14 constructor() { 19 constructor() {
15 this.initPlayerController() 20 this.initPlayerController()
16 } 21 }
@@ -23,6 +28,10 @@ export class AudioSuspensionModel { @@ -23,6 +28,10 @@ export class AudioSuspensionModel {
23 AppStorage.setOrCreate('playerController', new WDPlayerController()); 28 AppStorage.setOrCreate('playerController', new WDPlayerController());
24 this.playerController = AppStorage.link<WDPlayerController>('playerController') 29 this.playerController = AppStorage.link<WDPlayerController>('playerController')
25 Logger.info(TAG, 'playerController create success') 30 Logger.info(TAG, 'playerController create success')
  31 + this.playerController.get().onStatusChange = (status: number) => {
  32 + console.info(TAG, 'this.currentStatus', status)
  33 + EmitterUtils.sendEvent(EmitterEventId.AUDIO_CHANGE_STATUS, status)
  34 + }
26 } else { 35 } else {
27 Logger.info(TAG, 'playerController already exit') 36 Logger.info(TAG, 'playerController already exit')
28 } 37 }
@@ -30,32 +39,70 @@ export class AudioSuspensionModel { @@ -30,32 +39,70 @@ export class AudioSuspensionModel {
30 /** 39 /**
31 * 配置音频地址 40 * 配置音频地址
32 */ 41 */
33 - public setPlayerUrl() {  
34 - // this.playerController.switchPlayOrPause()  
35 - Logger.info(TAG, 'handlePlayer') 42 + public setPlayerUrl(url: string, srcTitle: string) {
  43 + // console.log(TAG,'this.url', this.url)
  44 + // console.log(TAG,'url', url)
  45 + if (this.url === url) {
  46 + this.playerController.get().switchPlayOrPause()
  47 + } else {
  48 + this.url = url
  49 + this.playerController.get().firstPlay(url)
  50 + this.playerController.get().onCanplay = () => {
  51 + this.playerController.get().play()
  52 + }
  53 + this.srcTitle = srcTitle
  54 + EmitterUtils.sendEvent(EmitterEventId.AUDIO_CHANGE_TITLe, this.srcTitle)
  55 + console.log(TAG, 'handlePlayer')
  56 + this.resizeWindow(this.expandWidth, this.expandHeight)
  57 + }
  58 + this.showWindow()
36 } 59 }
37 // 显示悬浮窗。 60 // 显示悬浮窗。
38 public showWindow() { 61 public showWindow() {
39 - this.floatWindowClass.get().showWindow((err: BusinessError) => { 62 + // 判断当前窗口是否已显示,使用callback异步回调。
  63 + this.floatWindowClass.get().isShowing((err: BusinessError, data) => {
  64 + const errCode: number = err.code;
  65 + if (errCode) {
  66 + console.error(TAG, 'Failed window is showing Cause:' + JSON.stringify(err));
  67 + return;
  68 + }
  69 + console.info(TAG, 'window is showing: ' + JSON.stringify(data));
  70 + if(data === false) {
  71 + // 显示当前窗口,使用callback异步回调。
  72 + this.floatWindowClass.get().showWindow((err: BusinessError) => {
  73 + let errCode: number = err.code;
  74 + if (errCode) {
  75 + console.error(TAG, 'floatWindowClass Failed to show the window. Cause: ' + JSON.stringify(err));
  76 + return;
  77 + }
  78 + console.info(TAG, 'floatWindowClass Succeeded in showing the window.');
  79 + });
  80 + }
  81 + });
  82 + }
  83 +
  84 + // 设置悬浮窗尺寸
  85 + public resizeWindow(width: number, height: number) {
  86 + this.floatWindowClass.get().resize(width, height, (err: BusinessError) => {
40 let errCode: number = err.code; 87 let errCode: number = err.code;
41 if (errCode) { 88 if (errCode) {
42 - console.error('floatWindowClass Failed to show the window. Cause: ' + JSON.stringify(err)); 89 + console.error(TAG, 'floatWindowClass Failed to change the window size. Cause:' + JSON.stringify(err));
43 return; 90 return;
44 } 91 }
45 - console.info('floatWindowClass Succeeded in showing the window.'); 92 + console.info(TAG, 'floatWindowClass Succeeded in changing the window size.');
46 }); 93 });
47 } 94 }
48 95
49 // 销毁悬浮窗 使用destroy对其进行销毁。 96 // 销毁悬浮窗 使用destroy对其进行销毁。
50 public destroyWindow() { 97 public destroyWindow() {
51 - this.floatWindowClass.get().destroyWindow((err: BusinessError) => { 98 + /*this.floatWindowClass.get().destroyWindow((err: BusinessError) => {
52 let errCode: number = err.code; 99 let errCode: number = err.code;
53 if (errCode) { 100 if (errCode) {
54 console.error('floatWindowClass Failed to destroy the window. Cause: ' + JSON.stringify(err)); 101 console.error('floatWindowClass Failed to destroy the window. Cause: ' + JSON.stringify(err));
55 return; 102 return;
56 } 103 }
57 console.info('floatWindowClass Succeeded in destroying the window.'); 104 console.info('floatWindowClass Succeeded in destroying the window.');
58 - }); 105 + });*/
59 } 106 }
60 107
61 108
@@ -17,6 +17,22 @@ export class DateFormatUtil { @@ -17,6 +17,22 @@ export class DateFormatUtil {
17 return `${'00'}${':'}${DateFormatUtil.padding(second.toString())}`; 17 return `${'00'}${':'}${DateFormatUtil.padding(second.toString())}`;
18 } 18 }
19 } 19 }
  20 + /**
  21 + * ms数转成00:00格式
  22 + * @param milliseconds
  23 + * @returns
  24 + */
  25 + static convertMillisecondsToMinutesSeconds(milliseconds: number): string {
  26 + const totalSeconds = Math.floor(milliseconds / 1000);
  27 + const minutes = Math.floor(totalSeconds / 60);
  28 + const seconds = totalSeconds % 60;
  29 +
  30 + // 添加前导零,确保格式为两位数
  31 + const formattedMinutes = String(minutes).padStart(2, '0');
  32 + const formattedSeconds = String(seconds).padStart(2, '0');
  33 +
  34 + return `${formattedMinutes}:${formattedSeconds}`;
  35 + }
20 36
21 static padding(num: string) { 37 static padding(num: string) {
22 let length = 2; 38 let length = 2;
@@ -23,6 +23,8 @@ import { ConfigurationConstant } from '@kit.AbilityKit'; @@ -23,6 +23,8 @@ import { ConfigurationConstant } from '@kit.AbilityKit';
23 import { WDPushNotificationManager } from 'wdHwAbility/Index'; 23 import { WDPushNotificationManager } from 'wdHwAbility/Index';
24 import { StartupManager } from '../startupmanager/StartupManager'; 24 import { StartupManager } from '../startupmanager/StartupManager';
25 25
  26 +let floatWindowClass: window.Window | null = null;
  27 +
26 export default class EntryAbility extends UIAbility { 28 export default class EntryAbility extends UIAbility {
27 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 29 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
28 StartupManager.sharedInstance().appOnCreate(want, launchParam, this.context) 30 StartupManager.sharedInstance().appOnCreate(want, launchParam, this.context)
@@ -82,7 +84,6 @@ export default class EntryAbility extends UIAbility { @@ -82,7 +84,6 @@ export default class EntryAbility extends UIAbility {
82 hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); 84 hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
83 }); 85 });
84 // 1.创建悬浮窗 86 // 1.创建悬浮窗
85 - let floatWindowClass: window.Window | null = null;  
86 const config: window.Configuration = { 87 const config: window.Configuration = {
87 name: "floatWindow", windowType: window.WindowType.TYPE_FLOAT, ctx: this.context 88 name: "floatWindow", windowType: window.WindowType.TYPE_FLOAT, ctx: this.context
88 }; 89 };
@@ -104,14 +105,6 @@ export default class EntryAbility extends UIAbility { @@ -104,14 +105,6 @@ export default class EntryAbility extends UIAbility {
104 } 105 }
105 console.info('floatWindowClass Succeeded in moving the window.'); 106 console.info('floatWindowClass Succeeded in moving the window.');
106 }); 107 });
107 - floatWindowClass.resize(800, 200, (err: BusinessError) => {  
108 - let errCode: number = err.code;  
109 - if (errCode) {  
110 - console.error('floatWindowClass Failed to change the window size. Cause:' + JSON.stringify(err));  
111 - return;  
112 - }  
113 - console.info('floatWindowClass Succeeded in changing the window size.');  
114 - });  
115 // 3.为悬浮窗加载对应的目标页面。 108 // 3.为悬浮窗加载对应的目标页面。
116 floatWindowClass.setUIContent("pages/view/AudioComponent", (err: BusinessError) => { 109 floatWindowClass.setUIContent("pages/view/AudioComponent", (err: BusinessError) => {
117 let errCode: number = err.code; 110 let errCode: number = err.code;
@@ -122,11 +115,27 @@ export default class EntryAbility extends UIAbility { @@ -122,11 +115,27 @@ export default class EntryAbility extends UIAbility {
122 console.info('floatWindowClass Succeeded in loading the content.'); 115 console.info('floatWindowClass Succeeded in loading the content.');
123 }); 116 });
124 117
  118 + floatWindowClass.on('windowEvent', (data) => {
  119 + EmitterUtils.sendEvent(EmitterEventId.AUDIO_WINDOW_TYPE, data)
  120 + });
  121 +
  122 + });
  123 + }
  124 +
  125 + destroyFloatWindow() {
  126 + (floatWindowClass as window.Window).destroyWindow((err: BusinessError) => {
  127 + let errCode: number = err.code;
  128 + if (errCode) {
  129 + console.error('floatWindowClass Failed to destroy the window. Cause: ' + JSON.stringify(err));
  130 + return;
  131 + }
  132 + console.info('floatWindowClass Succeeded in destroying the window.');
125 }); 133 });
126 } 134 }
127 135
128 onWindowStageDestroy(): void { 136 onWindowStageDestroy(): void {
129 // Main window is destroyed, release UI related resources 137 // Main window is destroyed, release UI related resources
  138 + this.destroyFloatWindow()
130 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); 139 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
131 } 140 }
132 141
1 import { AudioSuspensionModel } from 'wdComponent' 1 import { AudioSuspensionModel } from 'wdComponent'
2 -import { PlayerConstants } from 'wdPlayer' 2 +import { PlayerConstants, DateFormatUtil } from 'wdPlayer'
  3 +import { EmitterEventId, EmitterUtils } from 'wdKit/Index'
  4 +import window from '@ohos.window';
  5 +
  6 +const TAG = 'AudioSuspensionModel'
3 7
4 @Entry 8 @Entry
5 @Component 9 @Component
6 struct Index { 10 struct Index {
7 private AudioSuspension = new AudioSuspensionModel() 11 private AudioSuspension = new AudioSuspensionModel()
8 - @State audioTitle: string = '来了!新闻早班车5月9日';  
9 - @State currentTime: string = '00:03';  
10 - @State totalTime: string = '06:16';  
11 - @State progressVal: number = 20;  
12 - @State currentStatus: number = 0; 12 + @State audioTitle: string | undefined = '';
  13 + @State currentTime: string = '00:00';
  14 + @State totalTime: string = '00:00';
  15 + @State progressVal: number = 0;
  16 + @State currentStatus: number | string |undefined = 0;
  17 + @State isExpand: boolean = true;
  18 + private expandWidth: number = 800
  19 + private expandHeight: number = 200
  20 + private foldWidth: number = 200
  21 + private foldHeight: number = 200
  22 +
  23 + aboutToAppear() {
  24 + this.AudioSuspension.playerController.get().onTimeUpdate = (position, duration) => {
  25 + this.currentTime = DateFormatUtil.convertMillisecondsToMinutesSeconds(position);
  26 + this.totalTime = DateFormatUtil.convertMillisecondsToMinutesSeconds(duration);
  27 + this.progressVal = Math.floor(position * 100 / duration);
  28 + }
  29 +
  30 + EmitterUtils.receiveEvent(EmitterEventId.AUDIO_CHANGE_TITLe, (val:string | undefined) => {
  31 + console.log(TAG,'this.audioTitle', val)
  32 + this.audioTitle = val
  33 + })
  34 +
  35 + EmitterUtils.receiveEvent(EmitterEventId.AUDIO_CHANGE_STATUS, (val: number | string | undefined) => {
  36 + console.log(TAG,'this.currentStatus', val)
  37 + this.currentStatus = val
  38 + })
  39 +
  40 + EmitterUtils.receiveEvent(EmitterEventId.AUDIO_WINDOW_TYPE, (val: number | string | undefined) => {
  41 + if (val == window.WindowEventType.WINDOW_ACTIVE) {
  42 + console.info(TAG, 'current window stage event is WINDOW_ACTIVE', val);
  43 + this.isExpand = true
  44 + this.AudioSuspension.resizeWindow(this.expandWidth, this.expandHeight)
  45 + } else if (val == window.WindowEventType.WINDOW_INACTIVE) {
  46 + console.info(TAG, 'current window stage event is WINDOW_INACTIVE', val);
  47 + this.isExpand = false
  48 + this.AudioSuspension.resizeWindow(this.foldWidth, this.foldHeight)
  49 + }
  50 + })
  51 +
  52 + }
  53 +
  54 + onPageHide() {
  55 + // this.status = PlayerConstants.STATUS_PAUSE;
  56 + this.AudioSuspension.playerController.get()?.pause();
  57 + }
13 58
14 build() { 59 build() {
15 Stack({ alignContent: Alignment.End }) { 60 Stack({ alignContent: Alignment.End }) {
16 - Column() { //标题 时间 进度条  
17 - Marquee({  
18 - start: true,  
19 - step: 5,  
20 - loop: Number.POSITIVE_INFINITY,  
21 - fromStart: true,  
22 - src: this.audioTitle  
23 - })  
24 - .width("60%")  
25 - .height(20)  
26 - .fontColor('#222222')  
27 - .fontSize(14)  
28 - .margin({ top: 10, left: 10 })  
29 - .alignSelf(ItemAlign.Start)  
30 - .onStart(() => {  
31 - console.info('Marquee animation complete onStart') 61 + if(this.isExpand) {
  62 + Column() { //标题 时间 进度条
  63 + Marquee({
  64 + start: true,
  65 + step: 5,
  66 + loop: Number.POSITIVE_INFINITY,
  67 + fromStart: true,
  68 + src: this.audioTitle
32 }) 69 })
33 - .onBounce(() => {  
34 - console.info('Marquee animation complete onBounce')  
35 - })  
36 - .onFinish(() => {  
37 - console.info('Marquee animation complete onFinish')  
38 - })  
39 -  
40 - Row() {  
41 - Text(this.currentTime)  
42 - .fontSize(12)  
43 - .fontColor("#999999")  
44 - .height("100%")  
45 - .alignSelf(ItemAlign.Start)  
46 - Text("/" + this.totalTime)  
47 - .fontSize(12)  
48 - .fontColor("#999999")  
49 - .height("100%") 70 + .width("60%")
  71 + .height(20)
  72 + .fontColor('#222222')
  73 + .fontSize(14)
  74 + .margin({ top: 10, left: 10 })
50 .alignSelf(ItemAlign.Start) 75 .alignSelf(ItemAlign.Start)
  76 + .onStart(() => {
  77 + console.info('Marquee animation complete onStart')
  78 + })
  79 + .onBounce(() => {
  80 + console.info('Marquee animation complete onBounce')
  81 + })
  82 + .onFinish(() => {
  83 + console.info('Marquee animation complete onFinish')
  84 + })
51 85
52 - }  
53 - .width("100%")  
54 - .height(16)  
55 - .margin({ top: 4, left: 10 }) 86 + Row() {
  87 + Text(this.currentTime)
  88 + .fontSize(12)
  89 + .fontColor("#999999")
  90 + .height("100%")
  91 + .alignSelf(ItemAlign.Start)
  92 + Text("/" + this.totalTime)
  93 + .fontSize(12)
  94 + .fontColor("#999999")
  95 + .height("100%")
  96 + .alignSelf(ItemAlign.Start)
56 97
57 - Progress({ value: this.progressVal, total: 100, type: ProgressType.Capsule })  
58 - .color("#ED2800")  
59 - .backgroundColor($r('app.color.white')) 98 + }
60 .width("100%") 99 .width("100%")
61 - .height(3)  
62 - .margin({ top: 7 })  
63 - }  
64 - .width("100%")  
65 - .height("100%")  
66 - .justifyContent(FlexAlign.Start) 100 + .height(16)
  101 + .margin({ top: 4, left: 10 })
67 102
68 - Row() {  
69 - Image(this.currentStatus != PlayerConstants.STATUS_START ? $r("app.media.icon_audio_pause") : $r("app.media.icon_audio_playing"))  
70 - .objectFit(ImageFit.Contain)  
71 - .width(24)  
72 - .height(24)  
73 - .margin({ right: 12 })  
74 - .onClick(() => {  
75 - if (this.AudioSuspension.playerController) {  
76 - this.AudioSuspension.playerController.get().switchPlayOrPause()  
77 - this.currentStatus = this.AudioSuspension.playerController.get().getStatus()  
78 - }  
79 - }) 103 + Progress({ value: this.progressVal, total: 100, type: ProgressType.Capsule })
  104 + .color("#ED2800")
  105 + .backgroundColor($r('app.color.white'))
  106 + .width("100%")
  107 + .height(3)
  108 + .margin({ top: 7 })
  109 + }
  110 + .width("100%")
  111 + .height("100%")
  112 + .justifyContent(FlexAlign.Start)
80 113
81 - Image($r("app.media.icon_audio_close"))  
82 - .objectFit(ImageFit.Contain)  
83 - .width(24)  
84 - .height(24)  
85 - .onClick(() => {  
86 - if (this.AudioSuspension.playerController) {  
87 - this.AudioSuspension.playerController.get().stop()  
88 - this.AudioSuspension.destroyWindow()  
89 - }  
90 - })  
91 - }.width(80)  
92 - .height(60) 114 + Row() {
  115 + Image(this.currentStatus === PlayerConstants.STATUS_START ? $r("app.media.icon_audio_pause") : $r("app.media.icon_audio_playing"))
  116 + .objectFit(ImageFit.Contain)
  117 + .width(24)
  118 + .height(24)
  119 + .margin({ right: 12 })
  120 + .onClick(() => {
  121 + if (this.AudioSuspension.playerController) {
  122 + this.AudioSuspension.playerController.get().switchPlayOrPause()
  123 + }
  124 + })
93 125
  126 + Image($r("app.media.icon_audio_close"))
  127 + .objectFit(ImageFit.Contain)
  128 + .width(24)
  129 + .height(24)
  130 + .onClick(() => {
  131 + if (this.AudioSuspension.playerController) {
  132 + this.AudioSuspension.playerController.get().stop()
  133 + this.AudioSuspension.destroyWindow()
  134 + }
  135 + })
  136 + }.width(80)
  137 + .height(60)
  138 + } else {
  139 + Row() {
  140 + Image(this.currentStatus === PlayerConstants.STATUS_START ? $r("app.media.icon_audio_pause") : $r("app.media.icon_audio_playing"))
  141 + .objectFit(ImageFit.Contain)
  142 + .width(24)
  143 + .height(24)
  144 + .onClick(() => {
  145 + if (this.AudioSuspension.playerController) {
  146 + this.AudioSuspension.playerController.get().switchPlayOrPause()
  147 + }
  148 + })
  149 + }
  150 + .justifyContent(FlexAlign.Center)
  151 + .width(60)
  152 + .height(60)
  153 + }
94 } 154 }
95 .width('100%') 155 .width('100%')
96 .height('100%') 156 .height('100%')
@@ -92,9 +92,16 @@ @@ -92,9 +92,16 @@
92 { 92 {
93 "name": "ohos.permission.INTERNET" 93 "name": "ohos.permission.INTERNET"
94 }, 94 },
95 -// {  
96 -// "name": "ohos.permission.SYSTEM_FLOAT_WINDOW",  
97 -// } 95 + {
  96 + "name": "ohos.permission.SYSTEM_FLOAT_WINDOW",
  97 + "reason": "$string:EntryAbility_desc",
  98 + "usedScene": {
  99 + "abilities": [
  100 + "FormAbility"
  101 + ],
  102 + "when": "inuse"
  103 + }
  104 + }
98 ] 105 ]
99 } 106 }
100 } 107 }