소스 검색

:sparkless: add feature - audiobook play

zhanghe 6 년 전
부모
커밋
f7f7cf834a

+ 3 - 0
src/res/tpl/AudioWareFullScreen.tpl

@@ -0,0 +1,3 @@
+<div id="AudioWareFullScreen" fe-role="Switch">
+    <img id="wareImg" src="assets/img/default_bg.jpg" />
+</div>

+ 1 - 0
src/stage/index/index.less

@@ -29,3 +29,4 @@ body {
 @import './style/GlobalGoodDetail.less';
 @import './style/ImageWareFullScreen.less';
 @import './style/VideoWareFullScreen.less';
+@import './style/AudioWareFullScreen.less';

+ 269 - 0
src/stage/index/scene/AudioWareFullScreenScene.js

@@ -0,0 +1,269 @@
+import Consts from '../../../util/Consts';
+
+class AudioWareFullScreenScene extends scene {
+	constructor(scope) {
+		super(scope);
+		this.wareList = [];
+		this.curWareIndex = 0;
+		this.curWareType = null;
+		this.curAudioList = [];
+		this.curAudioIndex = 0;
+	}
+
+    /**
+     * 音频播放控制
+     */
+    audioPlayControl(eventId) {
+        let targetAudio = document.getElementById('courseware-audio');
+        if (!targetAudio) { return; }
+        const changeContent = () => {
+            // 更换图片
+            let imgDom = document.getElementById('img-wrapper');
+            let curAudio = this.curAudioList[this.curAudioIndex];
+            const { bgUrl, playUrl } = curAudio;
+            let newImg = `<img src="${Consts.IMG_PATH}/${bgUrl}" />`
+            imgDom.innerHTML = newImg;
+        }
+        switch (eventId) {
+            case 'audio-play':
+                let playBtn = document.querySelector('#audio-play');
+                if (targetAudio.paused) {
+                    targetAudio.play();
+                    playBtn.classList.remove('paused');
+                } else {
+                    targetAudio.pause();
+                    playBtn.classList.add('paused');
+                }
+                break;
+            case 'audio-mute':
+                let muteBtn = document.querySelector('#audio-mute');
+                if (targetAudio.muted) {
+                    targetAudio.muted = false;
+                    muteBtn.classList.remove('muted');
+                } else {
+                    targetAudio.muted = true;
+                    muteBtn.classList.add('muted');
+                }
+                break;
+            case 'audio-next':
+                if (this.curAudioIndex < this.curAudioList.length -1) {
+                    this.curAudioIndex += 1;
+                    this.renderAudioView();
+                }
+                break;
+            case 'audio-last':
+                if (this.curAudioIndex > 0) {
+                    this.curAudioIndex -= 1;
+                    this.renderAudioView();
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * 音频渲染
+     */
+	renderAudioView() {
+        const curAudio = this.curAudioList[this.curAudioIndex];
+        const { type, img, audio } = curAudio;
+        let imgPath = (img || {}).path || '';
+        let audioUrl = (audio || {}).url || '';
+        let content = document.getElementById('AudioWareFullScreen');
+        // 1.更换背景图片
+        let imgHTML = `<img src="${Consts.IMG_PATH}/${imgPath}" />`;
+        content.innerHTML = imgHTML;
+        // 2.根据是否有无audioURL来控制面板及audio的展现
+        if (type === Consts.TYPE_AUDIOBOOK && audioUrl) {
+            let audioElement = document.createElement('audio');
+            audioElement.setAttribute('id', 'courseware-audio');
+            audioElement.setAttribute('src', audioUrl);
+            let controlsElement = document.createElement('div');
+            controlsElement.setAttribute('class', 'audio-controls');
+            controlsElement.setAttribute('fe-role', 'Switch');
+            let controlsBtns = `
+                <!-- 播放/暂停 -->
+                <div id="audio-play" class="audio-controls-item btn-play paused" fe-role="Widget"></div>
+                <!-- 有声/静音 -->
+                <div id="audio-mute" class="audio-controls-item btn-mute" fe-role="Widget"></div>
+                <!-- 下一个音频 -->
+                <div id="audio-next" class="audio-controls-item btn-next" fe-role="Widget"></div>
+                <!-- 上一个音频 -->
+                <div id="audio-last" class="audio-controls-item btn-last" fe-role="Widget"></div>
+            `;
+            controlsElement.innerHTML = controlsBtns;
+            content.appendChild(audioElement);
+            content.appendChild(controlsElement);
+            this.moye.root.reRender();
+            FocusEngine.getWidgetById('audio-play').focus();
+        }
+	}
+
+	dynamicChangeWare(wareIndex, type) {
+		if (type === 'BACK') {
+			TVUtil.Toast.show('即将播放上个课件...', 1500);
+		} else if (type === 'NEXT') {
+			TVUtil.Toast.show('即将播放下个课件...', 1500);
+		}
+		setTimeout(() => {
+			this.curWareIndex = wareIndex;
+			this.curWareType = this.wareList[wareIndex].type;
+			//下一个或前一个课件是视频课件
+			if (this.curWareType === Consts.TYPE_VIDEO) {
+				this.hideScene();
+				this.showScene(require('./VideoWareFullScreenScene.js'), {
+					wareList: this.wareList,
+					curWareIndex: this.curWareIndex,
+				});
+            //下一个或前一个课件是图片课件
+            } else if (this.curWareType === Consts.TYPE_IMAGE) {
+                let imgList = this.wareList[this.curWareIndex].list;
+                let imgIndex = 0;
+                if (type === 'BACK' && imgList.length) {
+                    imgIndex = imgList.length - 1;
+                }
+                this.hideScene();
+        		this.showScene(require('./ImageWareFullScreenScene.js'), {
+        			wareList: this.wareList,
+        			curWareIndex: this.curWareIndex,
+        			curImageList: imgList,
+        			curImageIndex: imgIndex,
+        		});
+			//下一个或前一个课件是音频课件
+			} else {
+				this.curAudioList = this.wareList[wareIndex].list;
+				if (type === 'BACK') {
+					this.curAudioIndex = this.wareList[wareIndex].list.length - 1;
+				}
+				if (type === 'NEXT') {
+					this.curAudioIndex = 0;
+				}
+				this.renderAudioView();
+			}
+		}, 1500);
+	}
+
+	keyRightHandler() {
+		const hasNextWare = this.curWareIndex < this.wareList.length - 1 ? true : false;
+		//当前图片是该图片课件最后一张图片,且后边还有课件则切换课件
+		if (this.curAudioIndex === this.curAudioList.length - 1 && hasNextWare) {
+			const nextWareIndex = this.curWareIndex + 1;
+			this.dynamicChangeWare(nextWareIndex, 'NEXT')
+		//当前图片是该图片课件最后一张图片,且后边没有课件,给出提示
+		} else if (this.curAudioIndex === this.curAudioList.length - 1 && !hasNextWare) {
+			TVUtil.Toast.show('已经是最后一个课件了', 2000);
+		//当前图片不是该图片课件的最后一张图片
+    	} else {
+			this.curAudioIndex += 1;
+			this.renderAudioView();
+    	}
+	}
+
+	keyLeftHandler() {
+		const hasPreviousWare = this.curWareIndex === 0 ? false : true;
+		//当前图片是该图片课件的第一张图片,且前边还有课件
+	    if (this.curAudioIndex == 0 && hasPreviousWare) {
+			const previousWareIndex = this.curWareIndex - 1;
+			this.dynamicChangeWare(previousWareIndex, 'BACK');
+		//当前图片是该图片课件的第一张图片,且前边没有课件,则给出提示
+		} else if (this.curAudioIndex === 0 && !hasPreviousWare) {
+			TVUtil.Toast.show('已经是第一个课件了', 2000);
+		//当前图片不是该图片课件的第一张图片
+		} else {
+			this.curAudioIndex -= 1;
+			this.renderAudioView();
+		}
+	}
+
+	onCreate(data) {
+	    this.wareList = data.wareList;
+	    this.curWareIndex = data.curWareIndex;
+	    if (data.curAudioList) {
+			this.curAudioList = data.curAudioList;
+	    }
+	    if (data.curAudioIndex) {
+			this.curAudioIndex = data.curAudioIndex;
+	    }
+	    this.curWareType = this.wareList[this.curWareIndex].type;
+		this.setContentView(require('../../../res/tpl/AudioWareFullScreen.tpl'), {}, 'AudioWareFullScreen', {}, () => {
+			this.renderAudioView();
+		});
+	}
+
+	onResume() {
+
+	}
+
+	onPause() {
+
+	}
+
+	onDestroy() {
+
+	}
+
+	onActive() {
+
+	}
+
+	onInactive() {
+
+	}
+
+	onOK() {
+    	const leaf = FocusEngine.getFocusedLeaf();
+        // 拦截音频控制相关事件单独处理
+        if (leaf.id && leaf.id.startsWith('audio')) {
+            this.audioPlayControl(leaf.id);
+            return;
+        }
+	}
+
+	onBack() {
+
+	}
+
+	onKeyup() {
+
+	}
+
+	onKeydown(e) {
+		switch (e.keyCode) {
+			//左键
+			case 37:
+                // 如当前光标在控制按钮上,阻止向左
+                if (!FocusEngine.getFocusedLeaf().id.startsWith('audio')) {
+                    this.keyLeftHandler();
+                }
+				break;
+			//右键
+			case 39:
+                // 如当前光标在控制按钮上,阻止向右
+                if (!FocusEngine.getFocusedLeaf().id.startsWith('audio')) {
+                    this.keyRightHandler();
+                }
+				break;
+			//触屏设备向左滑动
+			case Consts.KEYCODE_CLICK_LEFT_SCREEN:
+				this.keyLeftHandler();
+				break;
+			//触屏设备向右滑动
+			case Consts.KEYCODE_CLICK_RIGHT_SCREEN:
+				this.keyRightHandler();
+				break;
+			//ESC键退出图片全屏
+			case 27:
+				this.hideScene({
+					curWareIndex: this.curWareIndex,
+					curAudioList: this.curAudioList,
+					curAudioIndex: this.curAudioIndex,
+				}, 'LessonScene');
+				break;
+			default:
+				break;
+		}
+	}
+}
+
+module.exports = AudioWareFullScreenScene;

+ 14 - 0
src/stage/index/scene/ImageWareFullScreenScene.js

@@ -31,6 +31,20 @@ class ImageWareFullScreenScene extends scene {
 					wareList: this.wareList,
 					curWareIndex: this.curWareIndex,
 				});
+            //下一个或前一个课件是音频课件
+			} else if (this.curWareType === Consts.TYPE_AUDIO) {
+                let imgList = this.wareList[this.curWareIndex].list;
+                let imgIndex = 0;
+                if (type === 'BACK' && imgList.length) {
+                    imgIndex = imgList.length - 1;
+                }
+                this.hideScene();
+                this.showScene(require('./AudioWareFullScreenScene.js'), {
+                    wareList: this.wareList,
+                    curWareIndex: this.curWareIndex,
+                    curAudioList: imgList,
+                    curAudioIndex: imgIndex,
+                });
 			//下一个或前一个课件是图片课件
 			} else {
 				this.curImageList = this.wareList[wareIndex].list;

+ 54 - 38
src/stage/index/scene/LessonScene.js

@@ -17,26 +17,26 @@ function matchWare(wareList, wareId) {
 
 class LessonScene extends scene {
     constructor(scope) {
-    super(scope);
-    this.timer = null;        //记录定时器
-    this.isBack = false;      //是否返回上个场景
-    this.videoPlayer = null;  //视频播放器
-    this.courseId = null;     //记录课程ID
-    this.lessonId = null;     //记录课ID
-    this.wareList = null;     //记录课件列表
-    this.curWareId = null;    //当前课件的id
-    this.curWareType = null;  //当前课件的类型
-    this.curWareIndex = 0;    //当前课件在课件列表中的索引
-    this.curImageList = null; //当前图片课件的图片列表
-    this.curImageIndex = null;//当前图片在列表中的索引
-    this.curAudioList = null; //当前音频课件的音频列表
-    this.curAudioIndex = 0;   //当前音频在列表中的索引
-    this.videoPosition = {
-    	top: 270,
-    	left: 790,
-    	width: 1072,
-    	height: 603,
-    };
+        super(scope);
+        this.timer = null;        //记录定时器
+        this.isBack = false;      //是否返回上个场景
+        this.videoPlayer = null;  //视频播放器
+        this.courseId = null;     //记录课程ID
+        this.lessonId = null;     //记录课ID
+        this.wareList = null;     //记录课件列表
+        this.curWareId = null;    //当前课件的id
+        this.curWareType = null;  //当前课件的类型
+        this.curWareIndex = 0;    //当前课件在课件列表中的索引
+        this.curImageList = null; //当前图片课件的图片列表
+        this.curImageIndex = null;//当前图片在列表中的索引
+        this.curAudioList = null; //当前音频课件的音频列表
+        this.curAudioIndex = 0;   //当前音频在列表中的索引
+        this.videoPosition = {
+        	top: 270,
+        	left: 790,
+        	width: 1072,
+        	height: 603,
+        };
     }
 
     /**
@@ -111,7 +111,7 @@ class LessonScene extends scene {
     		case Consts.TYPE_VIDEO:
     			item.icon = 'assets/img/LessonScene/video.png';
     			break;
-            case Consts.TYPE_AUDIO:
+            case Consts.TYPE_AUDIOBOOK:
                 item.icon = 'assets/img/LessonScene/audio.png';
     	}
     	return `<div class="ware-item-frame">
@@ -179,7 +179,7 @@ class LessonScene extends scene {
     				this.renderImageView();
     			}
     			break;
-            case Consts.TYPE_AUDIO:
+            case Consts.TYPE_AUDIOBOOK:
     			let audioViewDom =
     			`
     				<div id="view-full-screen" fe-role="Widget" class="view-full-screen-img"></div>
@@ -219,17 +219,19 @@ class LessonScene extends scene {
      */
     renderAudioView() {
         const curAudio = this.curAudioList[this.curAudioIndex];
-        const { url, audioUrl, type } = curAudio;
+        const { img, audio, type } = curAudio;
+        let imgPath = (img || {}).path || '';
+        let audioUrl = (audio || {}).url;
     	let footer = document.getElementById('view-page');
         if (footer) {
             footer.innerHTML = (this.curAudioIndex + 1) + '/' + this.curAudioList.length;
         }
         let content = document.getElementById('view-content');
         // 1.更换背景图片
-        let imgHTML = `<img src="${Consts.IMG_PATH}/${url}" />`;
+        let imgHTML = `<img src="${Consts.IMG_PATH}/${imgPath}" />`;
         content.innerHTML = imgHTML;
         // 2.根据是否有无audioURL来控制面板及audio的展现
-        if (type === Consts.TYPE_AUDIO && audioUrl) {
+        if (type === Consts.TYPE_AUDIOBOOK && audioUrl) {
             let audioElement = document.createElement('audio');
             audioElement.setAttribute('id', 'courseware-audio');
             audioElement.setAttribute('src', audioUrl);
@@ -250,7 +252,7 @@ class LessonScene extends scene {
             content.appendChild(audioElement);
             content.appendChild(controlsElement);
             this.moye.root.reRender();
-            FocusEngine.getWidgetById('audio-play').focus();
+            //FocusEngine.getWidgetById('audio-play').focus();
         }
     }
 
@@ -335,7 +337,7 @@ class LessonScene extends scene {
     			this.moye.root.reRender();
     			this.renderImageView();
     			break;
-    		case Consts.TYPE_AUDIO:
+    		case Consts.TYPE_AUDIOBOOK:
     			let audioViewDom =
     			`
     				<div id="view-full-screen" fe-role="Widget" class="view-full-screen-img"></div>
@@ -362,14 +364,6 @@ class LessonScene extends scene {
     audioPlayControl(eventId) {
         let targetAudio = document.getElementById('courseware-audio');
         if (!targetAudio) { return; }
-        const changeContent = () => {
-            // 更换图片
-            let imgDom = document.getElementById('img-wrapper');
-            let curAudio = this.curAudioList[this.curAudioIndex];
-            const { bgUrl, playUrl } = curAudio;
-            let newImg = `<img src="${Consts.IMG_PATH}/${bgUrl}" />`
-            imgDom.innerHTML = newImg;
-        }
         switch (eventId) {
             case 'audio-play':
                 let playBtn = document.querySelector('#audio-play');
@@ -445,7 +439,7 @@ class LessonScene extends scene {
     onResume(data) {
         if (!data) { return; }
         //更新下当前的课件信息
-        const { curWareIndex, curImageList, curImageIndex } = data;
+        const { curWareIndex, curImageList, curImageIndex, curAudioList, curAudioIndex } = data;
         this.curWareIndex = curWareIndex;
         this.curWareId = this.wareList[curWareIndex].id;
         this.curWareType = this.wareList[curWareIndex].type;
@@ -455,6 +449,12 @@ class LessonScene extends scene {
         if (curImageIndex) {
             this.curImageIndex = curImageIndex;
         }
+        if (curAudioList) {
+            this.curAudioList = curAudioList;
+        }
+        if (curAudioIndex) {
+            this.curAudioIndex = curAudioIndex;
+        }
         //更新左侧焦点位置
         this.moye.root.getWidgetById(`item-${this.curWareType}-${this.curWareId}-${this.curWareIndex}`).focus();
         //更新右侧视图
@@ -501,6 +501,22 @@ class LessonScene extends scene {
                         wareList: this.wareList,
                         curWareIndex: this.curWareIndex,
                     });
+                } else if (this.curWareType === Consts.TYPE_AUDIOBOOK) {
+                    // 全屏前移除audio标签
+                    let audio = document.getElementById('courseware-audio');
+                    let controls = document.querySelector('.audio-controls');
+                    if (audio) {
+                        document.getElementById('view-content').removeChild(audio);
+                    }
+                    if (controls) {
+                        document.getElementById('view-content').removeChild(controls);
+                    }
+                    this.showScene(require('./AudioWareFullScreenScene.js'), {
+            			wareList: this.wareList,
+            			curWareIndex: this.curWareIndex,
+            			curAudioList: this.curAudioList,
+            			curAudioIndex: this.curAudioIndex,
+                    });
                 }
     			this.postPlayRecord(this.cur_item_id, this.courseId);
     			break;
@@ -509,7 +525,7 @@ class LessonScene extends scene {
     				this.curImageIndex -= 1;
     				this.renderImageView();
     			}
-                if (this.curWareType === Consts.TYPE_AUDIO && this.curAudioIndex - 1 >= 0) {
+                if (this.curWareType === Consts.TYPE_AUDIOBOOK && this.curAudioIndex - 1 >= 0) {
                     this.curAudioIndex -= 1;
                     this.renderAudioView();
                 }
@@ -520,7 +536,7 @@ class LessonScene extends scene {
     				this.curImageIndex += 1;
     				this.renderImageView();
     			}
-                if (this.curWareType === Consts.TYPE_AUDIO && this.curAudioIndex + 1 < this.curAudioList.length) {
+                if (this.curWareType === Consts.TYPE_AUDIOBOOK && this.curAudioIndex + 1 < this.curAudioList.length) {
                     this.curAudioIndex += 1;
                     this.renderAudioView();
                 }

+ 21 - 2
src/stage/index/scene/VideoWareFullScreenScene.js

@@ -35,12 +35,31 @@ class VideoWareFullScreenScene extends scene {
                 this.initVideoPlayer(curWareItem);
             } else if (this.curWareType === Consts.TYPE_IMAGE) {
                 //进入到图片全屏场景
+                let imgList = curWareItem.list;
+                let imgIndex = 0;
+                if (type === 'BACK' && imgList.length) {
+                    imgIndex = imgList.length - 1;
+                }
                 this.hideScene();
                 this.showScene(require('./ImageWareFullScreenScene.js'), {
                     wareList: this.wareList,
                     curWareIndex: this.curWareIndex,
-                    curImageList: curWareItem.list,
-                    curImageIndex: 0,
+                    curImageList: imgList,
+                    curImageIndex: imgIndex,
+                });
+            } else if (this.curWareType === Consts.TYPE_AUDIO) {
+                //进入到音频全屏场景
+                let imgList = curWareItem.list;
+                let imgIndex = 0;
+                if (type === 'BACK' && imgList.length) {
+                    imgIndex = imgList.length - 1;
+                }
+                this.hideScene();
+                this.showScene(require('./AudioWareFullScreenScene.js'), {
+                    wareList: this.wareList,
+                    curWareIndex: this.curWareIndex,
+                    curAudioList: imgList,
+                    curAudioIndex: imgIndex,
                 });
             }
         }, 1500);

+ 65 - 0
src/stage/index/style/AudioWareFullScreen.less

@@ -0,0 +1,65 @@
+#AudioWareFullScreen {
+	position: absolute;
+	left: 0;
+	top: 0;
+	width: 100%;
+	height: 100%;
+	overflow: hidden;
+	background-image: url(assets/img/icon.png);
+	background-size: 100% 100%;
+	background-repeat: no-repeat;
+
+	img {
+		width: 100%;
+		height: 100%;
+	}
+
+	audio {
+		width: 100%;
+		height: 100%;
+	}
+
+	.audio-controls {
+		z-index: 10;
+		position: absolute;
+		left: 0;
+		bottom: .4rem;
+		width: 100%;
+		height: .7rem;
+		.audio-controls-item {
+			width: .6rem;
+			height: .6rem;
+			border: solid unit(@borderSize, rem) transparent;
+			border-radius: 50%;
+			background-size: 100% 100%;
+			background-repeat: no-repeat;
+			&.btn-play {
+				float: left;
+				margin-left: .2rem;
+				background-image: url(assets/img/Audio/audio_stop.png);
+				&.paused {
+					background-image: url(assets/img/Audio/audio_play.png);
+				}
+			}
+			&.btn-mute {
+				float: left;
+				background-image: url(assets/img/Audio/audio_mute.png);
+				&.muted {
+					background-image: url(assets/img/Audio/audio_voice.png);
+				}
+			}
+			&.btn-last {
+				float: right;
+				background-image: url(assets/img/Audio/audio_last.png);
+			}
+			&.btn-next {
+				float: right;
+				margin-right: .2rem;
+				background-image: url(assets/img/Audio/audio_next.png);
+			}
+			&.fe-focus {
+				.after-focus(@borderSize; #ffe100; .1rem; rgba(0,0,0,0.5));
+			}
+		}
+	}
+}

+ 3 - 15
src/stage/index/style/LessonScene.less

@@ -124,21 +124,9 @@
 				width: 100%;
 				height: 100%;
 			}
-			.img-wrapper {
-				width: 10.72rem;
-				height: 6.03rem;
-				img {
-					width: 100%;
-					height: 100%;
-				}
-			}
-			.audio-wrapper {
-				width: 10.72rem;
-				height: 6.03rem;
-				audio {
-					width: 100%;
-					height: 100%;
-				}
+			audio {
+				width: 100%;
+				height: 100%;
 			}
 			.audio-controls {
 				z-index: 10;

+ 1 - 0
src/util/Consts.js

@@ -18,6 +18,7 @@ Consts.VIDEO_PATH = 'http://ljvideo.ai160.com/vs2m';
 Consts.TYPE_VIDEO = 0;
 Consts.TYPE_AUDIO = 1;
 Consts.TYPE_IMAGE = 3;
+Consts.TYPE_AUDIOBOOK = 4;
 
 //产品类型
 Consts.TYPE_COURSE = 'COURSE';