UNPKG

principles-ui-components

Version:

Supporting UI controller for Tizen TV web application, which developed base on React Framework.

1,038 lines (940 loc) 42 kB
/** * @author Song Zhang (song8.zhang@samsung.com) and Haipeng Zhang(hp.zhang@samsung.com) * @fileoverview This module manages more fetch single list. * @date 2017/07/18 (last modified date) * * Copyright 2017 by Samsung Electronics, Inc., * * This software is the confidential and proprietary information * of Samsung Electronics, Inc. ("Confidential Information"). You * shall not disclose such Confidential Information and shall use * it only in accordance with the terms of the license agreement * you entered into with Samsung. */ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import Immutable, { List, Map } from 'immutable'; import { KEY, AnimationEffect, TTSTYPE } from './common/CommonDefine'; import CommonList from './CommonList'; import ScrollBar from './ScrollBar'; import TTS from './common/TTS'; import ScrollText from './common/ScrollText'; export default class SingleLineList extends Component { constructor(props) { super(props); this.handleKey = this.handleKey.bind(this); const { morefetchEnable, width, transLeft, details, gap, focusScale, initFocus, title } = this.props; this.focus = 'LIST1'; this.hasFocus = initFocus; this.pageData = []; // three page Data start and end this.scaleW = details[0].OSD.layout.w * (focusScale - 1); // one scale length 285*0.2 = 57 this.halfScaleW = this.scaleW / 2; this.listShowNum = Math.floor((width - transLeft - this.scaleW) / (details[0].OSD.layout.w + gap)); this.listNum = this.listShowNum + 2; // for edge issue console.log(`SingleLineList constructor listNum ${this.listNum}`); this.detailslen = details.length; this.commonList1Data = []; this.lastFocusOutPos = 0; this.titleAni = ''; if (this.detailslen <= this.listNum * 3 || !morefetchEnable) { // If not exceed 3 pages, no need to use morefetch console.log(`SingleLineList constructor listNum ${this.listNum}, detailslen ${this.detailslen}, no need to use morefetch!`); this.pageData.push({ start: 0, end: this.detailslen - 1, }); this.state = { titleAni: '', }; return true; } this.showData = []; // show data of the list this.hScrollPx = 0; this.hList1ScrollPx = transLeft; this.hList2ScrollPx = transLeft; // 80 285*8 = 1710 2*8 = 12 285*0.2 = 57 this.hList2ScrollPx += details[0].OSD.layout.w * this.listNum; this.hList2ScrollPx += gap * this.listNum; this.hList2ScrollPx += this.scaleW; this.hList3ScrollPx = this.hList2ScrollPx; // 80 285*6 = 1710 2*6 = 12 285*0.2 = 57 285*6 = 1710 2*6 = 12 this.hList3ScrollPx += details[0].OSD.layout.w * this.listNum; this.hList3ScrollPx += gap * this.listNum; this.hPagePx = this.hList3ScrollPx; // three page total length 3581 285*6 = 1710 2*6 = 12 -80 this.hPagePx += details[0].OSD.layout.w * this.listNum; this.hPagePx += gap * this.listNum; this.hPagePx -= transLeft; if (!this.hasFocus) { this.hList2ScrollPx -= this.scaleW; this.hList3ScrollPx -= this.scaleW; } this.hListPx = details[0].OSD.layout.w + gap; // one item move px this.detailslen = details.length; this.scrollBarTop = 0; let i = 0; for (i = 0; i < this.listShowNum; i++) { this.showData.push({ pageIndex: 1, listIndex: i, }); } this.pageData.push({ start: 0, end: this.listNum - 1, }); this.pageData.push({ start: this.listNum, end: (this.listNum * 2) - 1, }); this.pageData.push({ start: this.listNum * 2, end: (this.listNum * 3) - 1, }); this.commonList2Data = []; this.commonList3Data = []; this.transList1 = `all 0.3s ${AnimationEffect.Basic}`; this.transList2 = `all 0.3s ${AnimationEffect.Basic}`; this.transList3 = `all 0.3s ${AnimationEffect.Basic}`; this.scrollHPercent = 0; this.lastKey = 'keyup'; // title if (this.hasFocus && title !== undefined && title !== null) { this.titleAni = 'commonListFocusInAni'; } this.state = { scrollHPercent: 0, // Calculated when component mounted, because index is found by ref name, so it can only be calculated after component mounted. hScrollPx: 0, hList1ScrollPx: this.hList1ScrollPx, hList2ScrollPx: this.hList2ScrollPx, hList3ScrollPx: this.hList3ScrollPx, transList1: `all 0.3s ${AnimationEffect.Basic}`, transList2: `all 0.3s ${AnimationEffect.Basic}`, transList3: `all 0.3s ${AnimationEffect.Basic}`, titleAni: this.titleAni, }; } componentWillMount() { const { details, title, focusScale } = this.props; const halfScaleH = (details[0].OSD.layout.h * (focusScale - 1)) / 2; if (title !== undefined && title !== null) { this.style = document.createElement('style'); this.style.type = 'text/css'; const keyFrames = `@keyframes commonListFocusInAni { 0% {transform: translateY(0px) translateZ(100px);} 50% {transform: translateY(-${title.t}px) translateZ(100px);} 100% {transform: translateY(-${halfScaleH}px) translateZ(100px);} } @keyframes commonListFocusOutAni { 0% {transform: translateY(-${halfScaleH}px) translateZ(100px);} 100% {transform: translateY(0px) translateZ(100px);} } @keyframes commonListInitAni { 0% {transform: translateY(0px) translateZ(100px);} 100% {transform: translateY(0px) translateZ(100px);} } `; this.style.innerHTML = keyFrames; document.getElementsByTagName('head')[0].appendChild(this.style); } } componentDidMount() { } componentWillReceiveProps() { } shouldComponentUpdate(nextProps, nextState) { const needUpdate = (JSON.stringify(nextProps) !== JSON.stringify(this.props) || JSON.stringify(nextState) !== JSON.stringify(this.state)); return needUpdate; } componentWillUpdate() { } componentDidUpdate() { } componentWillUnmount() { this.removeStyleFromHeader(); } getFocusIndex() { const index = this.refs[this.focus].getFocusIndex(); const pageIndex = parseInt(this.focus.charAt(this.focus.length - 1), 10); return this.pageData[pageIndex - 1].start + index; } getListData(commonListData, pageNo) { const { details } = this.props; let i = 0; const start = this.pageData[pageNo].start; const end = this.pageData[pageNo].end; console.log(`SingleLineList pageData ${pageNo} start:${start}`); console.log(`SingleLineList pageData ${pageNo} end:${end}`); commonListData.splice(0, commonListData.length); for (i = start; i <= end; i++) { commonListData.push(details[i]); } } /** * get lastItem scroll width for the last item is not show all in screen * @name getLastItemScrollPx * @method * @memberof * @param */ getLastItemScrollPx() { // 1920 - 80 - 57 = 1783 1783/287 = 6.212 1- 0.212 = 0.788 *287 = 226 const { transLeft, width, gap, details, transRight } = this.props; let screenWidth = 0; let screenItemsNumT = 0; let screenItemsNum = 0; let lastScrollPx = 0; screenWidth = width - transLeft - this.scaleW; screenItemsNumT = screenWidth / (details[0].OSD.layout.w + gap); screenItemsNum = Math.floor(screenItemsNumT); lastScrollPx = (1 - (screenItemsNumT - screenItemsNum)) * (details[0].OSD.layout.w + gap); console.log(`[SingleLineList.js:getLastScrollPx] lastScrollPx = ${lastScrollPx}`); return lastScrollPx + transRight; } removeStyleFromHeader() { if (this.style) { document.getElementsByTagName('head')[0].removeChild(this.style); this.style = null; } } keyFocusIn(position) { if (this.hasFocus) { console.error('[SingleLineList.js:keyFocusIn] List already have focus, doing nothing.'); return false; } const { details, gap, transLeft, title } = this.props; this.hasFocus = true; // title if (title !== undefined && title !== null) { this.titleAni = 'commonListFocusInAni'; } if (position === null || position === undefined || position.x === 0) { this.refs[this.focus].keyFocusInByIndex(this.lastFocusOutPos); if (this.detailslen > this.listNum * 3 && this.props.morefetchEnable) { // If exceed 3 pages and use morefetch this.moveListInOut(1); const scroll = 'SCROLL'; this.refs[scroll].showBar(); if (this.props.ttsEnable) { this.playTTS(TTSTYPE.LIST); } } this.setState({ titleAni: this.titleAni, }); return true; } if (this.detailslen > this.listNum * 3 && this.props.morefetchEnable) { // If exceed 3 pages and use morefetch let i = 0; let pageIndex; let listIndex; let posX = transLeft; for (i = 0; i < this.listShowNum; i++) { posX += (details[0].OSD.layout.w + gap); if (posX > position.x) { break; } } if (i === this.listShowNum) { // focus last one pageIndex = this.showData[i - 1].pageIndex; listIndex = this.showData[i - 1].listIndex; this.focus = `LIST${pageIndex}`; this.refs[this.focus].keyFocusInByIndex(listIndex); } else { pageIndex = this.showData[i].pageIndex; listIndex = this.showData[i].listIndex; this.focus = `LIST${pageIndex}`; this.refs[this.focus].keyFocusInByIndex(listIndex); } this.moveListInOut(1); const scroll = 'SCROLL'; this.refs[scroll].showBar(); if (this.props.ttsEnable) { this.playTTS(TTSTYPE.LIST); } } else { this.refs[this.focus].keyFocusIn(position); } this.setState({ titleAni: this.titleAni, }); return true; } keyFocusOut() { if (!this.hasFocus) { console.error('[SingleLineList.js:keyFocusOut] List do not have focus, doing nothing.'); return false; } const { details, gap, transLeft, title } = this.props; this.lastFocusOutPos = this.refs[this.focus].getFocusIndex(); const pageIndex = parseInt(this.focus.charAt(this.focus.length - 1), 10); const listIndex = this.refs[this.focus].getFocusIndex(); const position = this.refs[this.focus].keyFocusOut(); this.hasFocus = false; this.lastKey = 'keyup'; if (this.detailslen > this.listNum * 3 && this.props.morefetchEnable) { // If exceed 3 pages and use morefetch this.moveListInOut(-1); // for near focus rule position.x = transLeft; let i = 0; for (i = 0; i < this.listShowNum; i++) { if (this.showData[i].pageIndex === pageIndex && this.showData[i].listIndex === listIndex) { position.x += (details[0].OSD.layout.w + gap) / 2; break; } position.x += (details[0].OSD.layout.w + gap); } } // title if (title !== undefined && title !== null) { this.titleAni = 'commonListFocusOutAni'; this.setState({ titleAni: this.titleAni, }); this.titleAni = 'commonListInitAni'; this.setState({ titleAni: this.titleAni, }); } return position; } playTTS(type) { if (type === TTSTYPE.LIST) { this.TTSnode.playTTS(); } else if (type === TTSTYPE.ITEM) { this.refs[this.focus].playTTS(TTSTYPE.ITEM); } } moveListInOut(direct) { if (direct !== 1 && direct !== -1) { console.error('[SingleLineList.js:moveListInOut] direct is wrong, doing nothing.'); return false; } if (this.focus === 'LIST1') { if (this.pageData[0].end !== this.detailslen - 1) { this.hList2ScrollPx += this.scaleW * direct; if (this.pageData[2].start > this.pageData[0].end) { // LIST3 is in the right of LIST1 this.hList3ScrollPx += this.scaleW * direct; } } } else if (this.focus === 'LIST2') { if (this.pageData[1].end !== this.detailslen - 1) { this.hList3ScrollPx += this.scaleW * direct; if (this.pageData[0].start > this.pageData[1].end) { // LIST1 is in the right of LIST2 this.hList1ScrollPx += this.scaleW * direct; } } } else if (this.focus === 'LIST3') { if (this.pageData[2].end !== this.detailslen - 1) { this.hList1ScrollPx += this.scaleW * direct; if (this.pageData[1].start > this.pageData[2].end) { // LIST2 is in the right of LIST3 this.hList2ScrollPx += this.scaleW * direct; } } } // last one let i = 0; for (i = 0; i < this.listShowNum; i++) { if (this.pageData[this.showData[i].pageIndex - 1].start + this.showData[i].listIndex === this.detailslen - 1) { this.hScrollPx -= this.scaleW * direct; break; } } this.setState({ hScrollPx: this.hScrollPx, hList1ScrollPx: this.hList1ScrollPx, hList2ScrollPx: this.hList2ScrollPx, hList3ScrollPx: this.hList3ScrollPx, transList1: `all 0.3s ${AnimationEffect.Basic}`, transList2: `all 0.3s ${AnimationEffect.Basic}`, transList3: `all 0.3s ${AnimationEffect.Basic}`, }); return true; } moveList(lastPageIndex, curPageIndex) { if (lastPageIndex === 2 && curPageIndex === 3) { // move 1 list right this.hList3ScrollPx -= this.scaleW; if (this.pageData[curPageIndex - 1].end === this.detailslen - 1) { this.transList1 = `all 0.3s ${AnimationEffect.Basic}`; this.transList2 = `all 0.3s ${AnimationEffect.Basic}`; this.transList3 = `all 0.3s ${AnimationEffect.Basic}`; } else { this.hList1ScrollPx += this.hPagePx; this.pageData[0].start = this.pageData[2].end + 1; this.pageData[0].end = this.pageData[2].end + this.listNum >= this.detailslen - 1 ? this.detailslen - 1 : this.pageData[2].end + this.listNum; console.log(`SingleLineList pageData 0 start:${this.pageData[0].start}`); console.log(`SingleLineList pageData 0 end:${this.pageData[0].end}`); this.transList1 = `all 0s ${AnimationEffect.Basic}`; this.transList2 = `all 0.3s ${AnimationEffect.Basic}`; this.transList3 = `all 0.3s ${AnimationEffect.Basic}`; } } else if (lastPageIndex === 3 && curPageIndex === 1) { // move 2 list right this.hList1ScrollPx -= this.scaleW; if (this.pageData[curPageIndex - 1].end === this.detailslen - 1) { this.transList1 = `all 0.3s ${AnimationEffect.Basic}`; this.transList2 = `all 0.3s ${AnimationEffect.Basic}`; this.transList3 = `all 0.3s ${AnimationEffect.Basic}`; } else { this.hList2ScrollPx += this.hPagePx; this.pageData[1].start = this.pageData[0].end + 1; this.pageData[1].end = this.pageData[0].end + this.listNum >= this.detailslen - 1 ? this.detailslen - 1 : this.pageData[0].end + this.listNum; console.log(`SingleLineList pageData 1 start:${this.pageData[1].start}`); console.log(`SingleLineList pageData 1 end:${this.pageData[1].end}`); this.transList1 = `all 0.3s ${AnimationEffect.Basic}`; this.transList2 = `all 0s ${AnimationEffect.Basic}`; this.transList3 = `all 0.3s ${AnimationEffect.Basic}`; } } else if (lastPageIndex === 1 && curPageIndex === 2) { // move 3 list right this.hList2ScrollPx -= this.scaleW; if (this.pageData[0].start > 0 && this.pageData[curPageIndex - 1].end !== this.detailslen - 1) { this.hList3ScrollPx += this.hPagePx; this.pageData[2].start = this.pageData[1].end + 1; this.pageData[2].end = this.pageData[1].end + this.listNum >= this.detailslen - 1 ? this.detailslen - 1 : this.pageData[1].end + this.listNum; console.log(`SingleLineList pageData 2 start:${this.pageData[2].start}`); console.log(`SingleLineList pageData 2 end:${this.pageData[2].end}`); this.transList1 = `all 0.3s ${AnimationEffect.Basic}`; this.transList2 = `all 0.3s ${AnimationEffect.Basic}`; this.transList3 = `all 0s ${AnimationEffect.Basic}`; } else { this.transList1 = `all 0.3s ${AnimationEffect.Basic}`; this.transList2 = `all 0.3s ${AnimationEffect.Basic}`; this.transList3 = `all 0.3s ${AnimationEffect.Basic}`; } } else if (lastPageIndex === 3 && curPageIndex === 2) { // move 1 list left this.hList3ScrollPx += this.scaleW; if (this.pageData[lastPageIndex - 1].end !== this.detailslen - 1) { this.hList1ScrollPx -= this.hPagePx; this.pageData[0].start = this.pageData[1].start - this.listNum; this.pageData[0].end = this.pageData[1].start - 1; console.log(`SingleLineList pageData 0 start:${this.pageData[0].start}`); console.log(`SingleLineList pageData 0 end:${this.pageData[0].end}`); this.transList1 = `all 0s ${AnimationEffect.Basic}`; this.transList2 = `all 0.3s ${AnimationEffect.Basic}`; this.transList3 = `all 0.3s ${AnimationEffect.Basic}`; } else { this.transList1 = `all 0.3s ${AnimationEffect.Basic}`; this.transList2 = `all 0.3s ${AnimationEffect.Basic}`; this.transList3 = `all 0.3s ${AnimationEffect.Basic}`; } } else if (lastPageIndex === 1 && curPageIndex === 3) { // move 2 list left this.hList1ScrollPx += this.scaleW; if (this.pageData[lastPageIndex - 1].end !== this.detailslen - 1) { this.hList2ScrollPx -= this.hPagePx; this.pageData[1].start = this.pageData[2].start - this.listNum; this.pageData[1].end = this.pageData[2].start - 1; console.log(`SingleLineList pageData 1 start:${this.pageData[1].start}`); console.log(`SingleLineList pageData 1 end:${this.pageData[1].end}`); this.transList1 = `all 0.3s ${AnimationEffect.Basic}`; this.transList2 = `all 0s ${AnimationEffect.Basic}`; this.transList3 = `all 0.3s ${AnimationEffect.Basic}`; } else { this.transList1 = `all 0.3s ${AnimationEffect.Basic}`; this.transList2 = `all 0.3s ${AnimationEffect.Basic}`; this.transList3 = `all 0.3s ${AnimationEffect.Basic}`; } } else if (lastPageIndex === 2 && curPageIndex === 1) { // move 3 list left this.hList2ScrollPx += this.scaleW; if (this.pageData[0].start > 0 && this.pageData[lastPageIndex - 1].end !== this.detailslen - 1) { this.hList3ScrollPx -= this.hPagePx; this.pageData[2].start = this.pageData[0].start - this.listNum; this.pageData[2].end = this.pageData[0].start - 1; console.log(`SingleLineList pageData 2 start:${this.pageData[2].start}`); console.log(`SingleLineList pageData 2 end:${this.pageData[2].end}`); this.transList1 = `all 0.3s ${AnimationEffect.Basic}`; this.transList2 = `all 0.3s ${AnimationEffect.Basic}`; this.transList3 = `all 0s ${AnimationEffect.Basic}`; } else { this.transList1 = `all 0.3s ${AnimationEffect.Basic}`; this.transList2 = `all 0.3s ${AnimationEffect.Basic}`; this.transList3 = `all 0.3s ${AnimationEffect.Basic}`; } } } moveLastItemR() { if (this.getFocusIndex() === this.detailslen - 1) { console.log('[SingleLineList.js:moveLastItem] Right.'); const lastItemScrollPx = this.getLastItemScrollPx(); this.hScrollPx += this.hListPx; this.hScrollPx -= lastItemScrollPx; } } moveLastItemL() { if (this.getFocusIndex() === this.detailslen - 1 - this.listShowNum) { console.log('[SingleLineList.js:moveLastItem] Left.'); const lastItemScrollPx = this.getLastItemScrollPx(); this.hScrollPx -= this.hListPx; this.hScrollPx += lastItemScrollPx; } } focusMove(direct) { let pageIndex = parseInt(this.focus.charAt(this.focus.length - 1), 10); const lastPageIndex = pageIndex; if ((pageIndex >= 3 && direct === 1)) { pageIndex = 1; } else if ((pageIndex <= 1 && direct === -1)) { pageIndex = 3; } else { pageIndex += direct; } const curPageIndex = pageIndex; this.moveList(lastPageIndex, curPageIndex); const position = this.refs[this.focus].keyFocusOut(); this.focus = `LIST${pageIndex}`; if (direct > 0) { // right this.refs[this.focus].keyFocusInByIndex(0); } else { // left this.refs[this.focus].keyFocusInByIndex(this.listNum - 1); } } adjustListPosition(event) { const { details, gap, width, transLeft } = this.props; const pageIndex = parseInt(this.focus.charAt(this.focus.length - 1), 10); const listIndex = this.refs[this.focus].getFocusIndex(); const totalLength = (details[0].OSD.layout.w + gap) * this.detailslen; const barLength = width - (transLeft * 2); const hiddenPx = totalLength - barLength; let scrollBarPx = 0; let i = 0; for (i = 0; i < this.listShowNum; i++) { if (this.showData[i].pageIndex === pageIndex && this.showData[i].listIndex === listIndex) { break; } } console.log(`SingleLineList adjustListPosition i:${i}`); // if need move if (i === this.listShowNum) { switch (event.keyCode) { case KEY.LEFT: this.hScrollPx += this.hListPx; this.moveLastItemL(); scrollBarPx = this.hScrollPx; if (scrollBarPx < 0) { scrollBarPx *= -1; } this.scrollHPercent = scrollBarPx / hiddenPx; // update show data for (i = this.listShowNum - 1; i >= 1; i--) { this.showData[i].pageIndex = this.showData[i - 1].pageIndex; this.showData[i].listIndex = this.showData[i - 1].listIndex; } this.showData[0].pageIndex = pageIndex; this.showData[0].listIndex = listIndex; break; case KEY.RIGHT: this.hScrollPx -= this.hListPx; this.moveLastItemR(); scrollBarPx = this.hScrollPx; if (scrollBarPx < 0) { scrollBarPx *= -1; } if (this.getFocusIndex() === this.detailslen - 1) { this.scrollHPercent = 1; } else { this.scrollHPercent = scrollBarPx / hiddenPx; } for (i = 0; i < this.listShowNum - 1; i++) { this.showData[i].pageIndex = this.showData[i + 1].pageIndex; this.showData[i].listIndex = this.showData[i + 1].listIndex; } this.showData[this.listShowNum - 1].pageIndex = pageIndex; this.showData[this.listShowNum - 1].listIndex = listIndex; break; default: // false: pass event to base component, true: not pass } } this.setState({ scrollHPercent: this.scrollHPercent, // Calculated when component mounted, because index is found by ref name, so it can only be calculated after component mounted. hScrollPx: this.hScrollPx, hList1ScrollPx: this.hList1ScrollPx, hList2ScrollPx: this.hList2ScrollPx, hList3ScrollPx: this.hList3ScrollPx, transList1: this.transList1, transList2: this.transList2, transList3: this.transList3, }); /* for (i = 0; i < this.listShowNum; i++) { console.log(`SingleLineList adjustListPosition all i:${i}, pageIndex:${this.showData[i].pageIndex}, listIndex:${this.showData[i].listIndex}`); }*/ } handleKey(event) { // when ever loading is showing, should not response keypress except for 'exit' key. console.log(`[SingleLineList.js] handleKey keyCode:${event.keyCode}`); if (this.detailslen <= this.listNum * 3 || !this.props.morefetchEnable) { // If not exceed 3 pages, no need to use morefetch this.refs[this.focus].handleKey(event); return true; } let pageIndex = 0; const scroll = 'SCROLL'; const list1 = 'LIST1'; const list2 = 'LIST2'; const list3 = 'LIST3'; switch (event.keyCode) { case KEY.LEFT: if ((this.refs[this.focus].getFocusIndex() === 0) && (this.focus === 'LIST1') && (this.pageData[0].start === 0)) { console.log('SingleLineList on the first one!'); if ((event.type === 'keydown' && this.lastKey === 'keydown') || (event.type === 'keyup' && this.lastKey === 'keydown') || (event.type === 'keyup' && this.lastKey === 'keyup')) { this.lastKey = event.type; return false; } this.lastKey = event.type; this.refs[this.focus].handleBounce(-1); } else { if (event.type === 'keyup') { return false; } if (this.refs[this.focus].getFocusIndex() === 0) { this.focusMove(-1); } else { this.refs[this.focus].handleKey(event); } this.adjustListPosition(event); this.playTTS(TTSTYPE.ITEM); } if (this.refs[scroll]) { this.refs[scroll].showBar(); } break; case KEY.RIGHT: if (this.getFocusIndex() === this.detailslen - 1) { console.log('SingleLineList on the last one!'); if ((event.type === 'keydown' && this.lastKey === 'keydown') || (event.type === 'keyup' && this.lastKey === 'keydown') || (event.type === 'keyup' && this.lastKey === 'keyup')) { this.lastKey = event.type; return false; } this.lastKey = event.type; this.refs[list1].handleBounce(1); this.refs[list2].handleBounce(1); this.refs[list3].handleBounce(1); } else { if (event.type === 'keyup') { return false; } pageIndex = parseInt(this.focus.charAt(this.focus.length - 1), 10); if (this.pageData[pageIndex - 1].end !== this.detailslen - 1 && this.refs[this.focus].getFocusIndex() === this.listNum - 1) { this.focusMove(1); } else { this.refs[this.focus].handleKey(event); } this.adjustListPosition(event); this.playTTS(TTSTYPE.ITEM); } if (this.refs[scroll]) { this.refs[scroll].showBar(); } break; default: // false: pass event to base component, true: not pass } return true; } render() { console.log('SingleLineList render'); const { morefetchEnable, width, height, transLeft, scrollBarEnable, focusScale, maxScale, gap, details, enter, enterCB } = this.props; const { top, contentTop, scrollBarTop, initFocus, initIndex, bounceEnable, bounceDelay, ttsEnable, ttsText, transRight, firstItemMoveEnable, title } = this.props; const { titleAni } = this.state; // app list this.getListData(this.commonList1Data, 0); let transLeftParm = 0; let scrollBarEnableParam = false; let morefetchEnableParam = true; let transRightParam = 0; let titleParam; let firstItemMoveEnableParam = firstItemMoveEnable; if (this.detailslen <= this.listNum * 3 || !morefetchEnable) { // If not exceed 3 pages, no need to use morefetch transLeftParm = transLeft; scrollBarEnableParam = true; morefetchEnableParam = false; transRightParam = transRight; titleParam = title; } if (this.pageData[0].start !== 0) { firstItemMoveEnableParam = true; // morefetch needs to move in the first item } const list1Component = (<CommonList details={this.commonList1Data} initFocus={initFocus} initIndex={initIndex} transLeft={transLeftParm} transRight={transRightParam} ref='LIST1' enter={enter} enterCB={enterCB} transition={`all 0.2s ${AnimationEffect.Basic}`} width={width} height={height} top={top} contentTop={contentTop} scrollBarTop={scrollBarTop} focusScale={focusScale} maxScale={maxScale} gap={gap} scrollBarEnable={scrollBarEnableParam} morefetchEnable={morefetchEnableParam} bounceEnable={bounceEnable} bounceDelay={bounceDelay} ttsEnable={ttsEnable} ttsText={ttsText} firstItemMoveEnable={firstItemMoveEnableParam} title={titleParam} />); if (this.detailslen <= this.listNum * 3 || !morefetchEnable) { // If not exceed 3 pages, no need to use morefetch return (<div> {list1Component} </div> ); } const { scrollHPercent, hScrollPx, hList1ScrollPx, hList2ScrollPx, hList3ScrollPx, transList1, transList2, transList3 } = this.state; this.getListData(this.commonList2Data, 1); this.getListData(this.commonList3Data, 2); const list2Component = (<CommonList details={this.commonList2Data} initFocus={false} initIndex={initIndex} transLeft={0} transRight={0} ref='LIST2' enter={enter} enterCB={enterCB} transition={`all 0.2s ${AnimationEffect.Basic}`} width={width} height={height} top={top} contentTop={contentTop} scrollBarTop={scrollBarTop} focusScale={focusScale} maxScale={maxScale} gap={gap} scrollBarEnable={scrollBarEnableParam} morefetchEnable={morefetchEnableParam} bounceEnable={bounceEnable} bounceDelay={bounceDelay} ttsEnable={ttsEnable} title={titleParam} />); const list3Component = (<CommonList details={this.commonList3Data} initFocus={false} initIndex={initIndex} transLeft={0} transRight={0} ref='LIST3' enter={enter} enterCB={enterCB} transition={`all 0.2s ${AnimationEffect.Basic}`} width={width} height={height} top={top} contentTop={contentTop} scrollBarTop={scrollBarTop} focusScale={focusScale} maxScale={maxScale} gap={gap} scrollBarEnable={scrollBarEnableParam} morefetchEnable={morefetchEnableParam} bounceEnable={bounceEnable} bounceDelay={bounceDelay} ttsEnable={ttsEnable} />); if (height === 0) { this.listheight = details[0].OSD.layout.h * maxScale; } else { this.listheight = height; } // list style const listStyle = { position: 'relative', width, height: this.listheight, // list height overflow: 'hidden', top, }; const contentStyle = { position: 'absolute', transform: `translateX(${hScrollPx}px)`, transition: `all 0.3s ${AnimationEffect.Basic}`, }; const list1Style = { position: 'absolute', transform: `translateX(${hList1ScrollPx}px) translateZ(10px)`, transition: transList1, }; const list2Style = { position: 'absolute', transform: `translateX(${hList2ScrollPx}px) translateZ(10px)`, transition: transList2, }; const list3Style = { position: 'absolute', transform: `translateX(${hList3ScrollPx}px) translateZ(10px)`, transition: transList3, }; if (scrollBarTop === 0) { this.scrollBarTop = details[0].OSD.layout.h * maxScale; } else { this.scrollBarTop = scrollBarTop; } // scrollbar let scrollbarComponent = null; const totalLength = (details[0].OSD.layout.w + gap) * this.detailslen; const scrollLeft = firstItemMoveEnable ? transLeft : (transLeft - this.halfScaleW); const barLength = width - (scrollLeft * 2); if (scrollBarEnable && this.hasFocus && totalLength > barLength) { scrollbarComponent = (<ScrollBar ref='SCROLL' left={scrollLeft} top={this.scrollBarTop} barType='h' bgWidth={barLength} bgHeight={3} barPercent={barLength / totalLength} scrollPercent={scrollHPercent} />); } // TTS let TTSComponent = null; if (ttsEnable) { TTSComponent = <TTS ref={(TTSnode) => { this.TTSnode = TTSnode; }} ttsEnable={ttsEnable} ttsText={ttsText} />; } // title const titleStyle = { position: 'absolute', }; let titleComponent = null; if (title !== undefined && title !== null) { if (this.titleAni !== '') { titleStyle.animationName = titleAni; titleStyle.animationDelay = '0.083s'; titleStyle.animationIterationCount = '1'; titleStyle.animationDuration = '0.7s'; titleStyle.animationTimingFunction = 'cubic-bezier(0.3,0,0.15,1)'; titleStyle.animationFillMode = 'forwards'; } titleComponent = (<ScrollText top={title.t} left={title.l} width={title.w} height={title.h} lineHeight={`${title.h}px`} scroll={false} fontSize={title.fontSize} fontFamily={title.fontFamily} color={title.color} > {title.text} </ScrollText>); } return (<div> <div style={listStyle}> <div style={titleStyle}> {titleComponent} </div> <div style={contentStyle}> <div style={list1Style}> {list1Component} </div> <div style={list2Style}> {list2Component} </div> <div style={list3Style}> {list3Component} </div> </div> </div> {scrollbarComponent} {TTSComponent} </div> ); } } SingleLineList.defaultProps = { morefetchEnable: true, // flag for whether to use morefetch function width: 1920, // width of display window of the list. height: 0, transLeft: 0, // when you want to move the list, but don't want to move display window, use this value. transRight: 0, // lastItem margin right top: 0, // same meaning as html top. it's used for display window. contentTop: 0, scrollBarTop: 0, focusScale: 1.2, maxScale: 1.3, gap: 2, scrollBarEnable: true, enter: false, // if enter pressed. enterCB: null, // enter call back. initFocus: false, initIndex: 0, bounceEnable: true, // bounce back animation name. aviable value: bounce1/bounce2. bounceDelay: 0, // delay time for bounce animation. ttsEnable: false, ttsText: '', firstItemMoveEnable: true, title: undefined, }; SingleLineList.propTypes = { morefetchEnable: PropTypes.bool, // flag for whether to use morefetch function width: PropTypes.number, height: PropTypes.number, transLeft: PropTypes.number, transRight: PropTypes.number, top: PropTypes.number, contentTop: PropTypes.number, scrollBarTop: PropTypes.number, focusScale: PropTypes.number, maxScale: PropTypes.number, gap: PropTypes.number, scrollBarEnable: PropTypes.bool, enter: PropTypes.bool, enterCB: PropTypes.func, initFocus: PropTypes.bool, // List has focus or not initIndex: PropTypes.number, bounceEnable: PropTypes.bool, // bounce back animation name. aviable value: bounce1/bounce2. bounceDelay: PropTypes.number, // delay time for bounce animation. ttsEnable: PropTypes.bool, ttsText: PropTypes.string, firstItemMoveEnable: PropTypes.bool, title: PropTypes.shape({ l: PropTypes.number, t: PropTypes.number, w: PropTypes.number, h: PropTypes.number, fontSize: PropTypes.number, text: PropTypes.string, fontFamily: PropTypes.string, color: PropTypes.string, }), details: PropTypes.arrayOf(PropTypes.shape({ OSD: PropTypes.shape({ // UI content for ImageItem layout: PropTypes.shape({ l: PropTypes.number.isRequired, t: PropTypes.number.isRequired, w: PropTypes.number.isRequired, h: PropTypes.number.isRequired, }), image: PropTypes.array, icon: PropTypes.array, text: PropTypes.array, ttsText: PropTypes.string, progress: PropTypes.shape({ l: PropTypes.number, t: PropTypes.number, w: PropTypes.number, h: PropTypes.number, rate: PropTypes.number, }), }), })).isRequired, };