张善主

Merge remote-tracking branch 'origin/main'

Showing 35 changed files with 996 additions and 283 deletions
import { StringUtils } from './StringUtils';
import getLunar from './GetLunar'
import getLunar from './GetLunar';
/**
* 日期/时间工具
*/
... ... @@ -480,6 +481,34 @@ export class DateTimeUtils {
return 0
}
}
/**
* 进度值换算
* @param seconds
* @returns
*/
static secondToTime(seconds: number) {
let time = '00:00'
let hourUnit = 60 * 60;
let hour = Math.floor(seconds / hourUnit);
let minute = Math.floor((seconds - hour * hourUnit) / 60);
let second = seconds - hour * hourUnit - minute * 60;
if (hour > 0) {
return `${DateTimeUtils.padding(hour.toString())}${':'}${DateTimeUtils.padding(minute.toString())}${':'}${DateTimeUtils.padding(second.toString())}`;
}
if (minute > 0) {
return `${DateTimeUtils.padding(minute.toString())}${':'}${DateTimeUtils.padding(second.toString())}`;
} else {
return `${'00'}${':'}${DateTimeUtils.padding(second.toString())}`;
}
}
static padding(num: string) {
let length = 2;
for (let len = (num.toString()).length; len < length; len = num.length) {
num = `${'0'}${num}`;
}
return num;
}
}
// const dateTimeUtils = new DateTimeUtils()
\ No newline at end of file
... ...
import HashMap from '@ohos.util.HashMap'
import { ConfigConstants, SpConstants } from 'wdConstant'
import { DateTimeUtils, Logger, SPHelper, StringUtils } from 'wdKit'
import HashMap from '@ohos.util.HashMap';
import { SpConstants } from 'wdConstant';
import { SPHelper, StringUtils } from 'wdKit';
/**
* 网络请求业务侧工具类
... ... @@ -213,6 +213,18 @@ export class HttpUrlUtils {
*/
static readonly LIVE_CHAT_LIST_PATH: string = "/api/live-center-message/zh/a/live/message/chat/list";
/**
* 直播详情-直播数据
*/
static readonly LIVE_ROOM_DATA_PATH: string = "/api/live-center-message/zh/a/live/room/number/all";
/**
* 直播详情-预约直播状态
*/
static readonly LIVE_APPOINTMENT_STATUS_PATH: string = "/api/live-center-message/zh/c/live/subscribe/query";
/**
* 直播详情-预约/取消预约直播
*/
static readonly LIVE_APPOINTMENT_PATH: string = "/api/live-center-message/zh/c/live/subscribe";
/**
* 搜索结果 显示tab 数
*/
... ... @@ -653,6 +665,21 @@ export class HttpUrlUtils {
return url
}
static getLiveRoomDataUrl() {
let url = HttpUrlUtils._hostUrl + HttpUrlUtils.LIVE_ROOM_DATA_PATH
return url
}
static getLiveAppointmentStatusUrl() {
let url = HttpUrlUtils._hostUrl + HttpUrlUtils.LIVE_APPOINTMENT_STATUS_PATH
return url
}
static getLiveAppointmentUrl() {
let url = HttpUrlUtils._hostUrl + HttpUrlUtils.LIVE_APPOINTMENT_PATH
return url
}
static getSearchResultCountDataUrl() {
let url = HttpUrlUtils._hostUrl + HttpUrlUtils.SEARCH_RESULT_COUNT_DATA_PATH
return url
... ...
... ... @@ -120,3 +120,5 @@ export { appStyleImagesDTO } from './src/main/ets/bean/content/appStyleImagesDTO
export { LiveRoomBean,LiveRoomItemBean } from './src/main/ets/bean/live/LiveRoomBean';
export { LiveRoomDataBean } from './src/main/ets/bean/live/LiveRoomDataBean';
... ...
... ... @@ -29,4 +29,9 @@ export interface CompDTO {
subType: string;
imageScale: number; // 封面图比例 1-4:3, 2-16:9, 3-3:2
audioDataList: AudioDTO[];
/**
* 组件内容源类型 (LIVE_HORIZONTAL_CARD\LIVE_RESERVATION\LIVE_LARGE_CARD\LIVE_END\LIVE_MONTHLY_RANKING )
*/
dataSourceType: string;
}
\ No newline at end of file
... ...
... ... @@ -2,6 +2,7 @@ import { CompDTO } from './CompDTO';
/**
* Page数据DTO
* 其实是comp接口(display/zh/c/compInfo)返回
*/
export interface PageDTO {
pageId: string; // 页面id
... ...
... ... @@ -158,9 +158,12 @@ export interface LiveDetailsBean {
*/
liveInfo: LiveInfo
fullColumnImgUrls: Array<FullColumnImgUrls>
vlive: Array<Vlive>
newsTitle: string
newsId: string
newIntroduction: string
//迁移id
oldNewsId: string
reLInfo: ReLInfo
}
export interface LiveInfo {
... ... @@ -168,6 +171,8 @@ export interface LiveInfo {
liveState: string
//2024-04-12 15:00:00 直播开始时间
planStartTime: string
mliveId:string
vlive: Array<Vlive>
}
export interface FullColumnImgUrls {
... ... @@ -179,4 +184,8 @@ export interface Vlive {
liveUrl: string
//直播回看地址,多路直播录制文件URL
replayUri: string
}
export interface ReLInfo {
relId: string
}
\ No newline at end of file
... ...
export interface LiveRoomDataBean {
barrageNum: number,
likeNum: number,
liveId: number,
pv: number,
subscribeNum: number,
}
\ No newline at end of file
... ...
import { CollectionUtils, DateTimeUtils, Logger } from 'wdKit';
import { CommonConstants, CompStyle, ViewType } from 'wdConstant';
import { CommonConstants, ViewType } from 'wdConstant';
import { Logger } from 'wdKit';
import PageViewModel from '../../viewmodel/PageViewModel';
import { EmptyComponent } from '../view/EmptyComponent';
import { ErrorComponent } from '../view/ErrorComponent';
... ... @@ -11,9 +11,8 @@ import NoMoreLayout from './NoMoreLayout';
import LoadMoreLayout from './LoadMoreLayout';
import CustomRefreshLoadLayout from './CustomRefreshLoadLayout';
import { CompParser } from '../CompParser';
import { GroupInfoDTO } from 'wdBean/src/main/ets/bean/navigation/PageInfoDTO';
import { CompDTO, LiveReviewDTO, PageDTO, PageInfoBean } from 'wdBean';
import { CompDTO } from 'wdBean';
import PageHelper from '../../viewmodel/PageHelper';
const TAG = 'PageComponent';
... ... @@ -23,22 +22,6 @@ export struct PageComponent {
navIndex: number = 0;
pageId: string = "";
channelId: string = "";
pageNum: number = 1;
isFirstIn: boolean = true
pageDto: PageDTO = {
pageId: '',
id: 0,
name: '',
branchMark: false,
compList: []
}
liveReviewDTO: LiveReviewDTO = {
hasNext: false,
pageNum: 0,
pageSize: 0,
totalCount: 0,
list: []
};
@Link @Watch('onChange') currentTopNavSelectedIndex: number
build() {
... ... @@ -69,7 +52,6 @@ export struct PageComponent {
@Builder
ListLayout() {
List() {
// 下拉刷新
ListItem() {
RefreshLayout({
... ... @@ -99,7 +81,6 @@ export struct PageComponent {
NoMoreLayout()
}
}
}
.scrollBar(BarState.Off)
.cachedCount(8)
... ... @@ -122,171 +103,32 @@ export struct PageComponent {
async aboutToAppear() {
// 选中tab,才请求数据。拦截大量接口请求
if (this.navIndex === 0 && this.navIndex === this.currentTopNavSelectedIndex) {
if (this.navIndex === this.currentTopNavSelectedIndex) {
this.getData();
} else if (this.navIndex === 1) {
this.getPreviewData()
}
}
onChange() {
Logger.info(TAG, `onChangezz id: ${this.pageId} , ${this.channelId} , ${this.navIndex} , ${this.isFirstIn} , navIndex: ${this.currentTopNavSelectedIndex}`);
// if (this.navIndex === this.currentTopNavSelectedIndex && !this.isFirstIn) {
Logger.info(TAG, `onChangezz id: ${this.pageId} , ${this.channelId} , ${this.navIndex} , navIndex: ${this.currentTopNavSelectedIndex}`);
if (this.navIndex === this.currentTopNavSelectedIndex) {
this.getData();
}
}
/**
* 要按顺序处理pageInfo.groups中的每个元素,并确保每个异步操作完成后再继续执行下一个,你应该避免使用forEach。
* 取而代之的是,你可以使用for...of循环,并配合async/await来确保按顺序执行操作。
* */
async getData() {
Logger.info(TAG, `getData id: ${this.pageId} , ${this.channelId} , navIndex: ${this.currentTopNavSelectedIndex}`);
this.pageModel.pageId = this.pageId;
this.pageModel.groupId = this.pageId;
this.pageModel.channelId = this.channelId;
this.pageModel.currentPage = 1;
let pageInfo = await PageViewModel.getPageUrlData(this.pageModel.pageId);
let pageInfo = await PageViewModel.getPageInfo(this.pageModel.pageId);
if (pageInfo == null) {
this.pageModel.viewType = ViewType.EMPTY;
return;
}
if (this.navIndex === 0) {
await this.getVideoListData(pageInfo);
} else {
await this.getLiveListData(pageInfo);
}
}
private async getVideoListData(pageInfo: PageInfoBean) {
let groupInfo: GroupInfoDTO = CollectionUtils.getElement(pageInfo.groups, 0);
if (groupInfo != null) {
this.pageModel.isRecGroup = groupInfo.groupStrategy === 1;
this.pageModel.groupId = groupInfo.id;
}
// pageInfo.groups.forEach(async (group) => { 不能按顺序加载用for...of替代
// for (const group of pageInfo.groups) {
this.pageDto = await PageViewModel.getPageData(this.pageModel, getContext(this));
this.pageModel.timestamp = DateTimeUtils.getTimeStamp().toString();
if (this.pageDto && this.pageDto.compList && this.pageDto.compList.length > 0) {
this.pageDto.compList.forEach((comp) => {
if (comp.compStyle === CompStyle.Zh_Grid_Layout_02 && this.liveReviewDTO && this.liveReviewDTO.list && this.liveReviewDTO.list.length > 0) {
comp.operDataList.push(...this.liveReviewDTO.list);
}
});
this.pageModel.viewType = ViewType.LOADED;
this.pageModel.compList.push(...this.pageDto.compList);
if (this.pageDto.compList.length === this.pageModel.pageSize) {
this.pageModel.currentPage++;
this.pageModel.hasMore = true;
} else {
this.pageModel.hasMore = false;
}
// // 二次请求,批查互动数据
// PageViewModel.getInteractData(pageDto.compList).then((data: CompDTO[]) => {
// // 刷新,替换所有数据
// this.pageModel.compList.replaceAll(...data)
// this.pageModel.timestamp = DateTimeUtils.getTimeStamp().toString()
// })
this.isFirstIn = false;
Logger.debug(TAG, 'cj111');
// } else {
// Logger.debug(TAG, 'aboutToAppear, data response page ' + this.pageId + ', comp list is empty.');
// this.pageModel.viewType = ViewType.EMPTY;
// }
}
}
// private async getLiveListData(pageInfo: PageInfoBean) {
// // pageInfo.groups.forEach(async (group) => { 不能按顺序加载用for...of替代
// for (const group of pageInfo.groups) {
// this.pageDto = await PageViewModel.getPageData(this.pageModel, getContext(this));
// this.pageModel.timestamp = DateTimeUtils.getTimeStamp().toString();
// if (this.pageDto && this.pageDto.compList && this.pageDto.compList.length > 0) {
// this.pageDto.compList.forEach((comp) => {
// if (comp.compStyle === CompStyle.Zh_Grid_Layout_02 && this.liveReviewDTO && this.liveReviewDTO.list && this.liveReviewDTO.list.length > 0) {
// comp.operDataList.push(...this.liveReviewDTO.list);
// }
// });
//
// this.pageModel.viewType = ViewType.LOADED;
// this.pageModel.compList.push(...this.pageDto.compList);
// if (this.pageDto.compList.length === this.pageModel.pageSize) {
// this.pageModel.currentPage++;
// this.pageModel.hasMore = true;
// } else {
// this.pageModel.hasMore = false;
// }
// // // 二次请求,批查互动数据
// // PageViewModel.getInteractData(pageDto.compList).then((data: CompDTO[]) => {
// // // 刷新,替换所有数据
// // this.pageModel.compList.replaceAll(...data)
// // this.pageModel.timestamp = DateTimeUtils.getTimeStamp().toString()
// // })
// this.isFirstIn = false;
// Logger.debug(TAG, 'cj111');
// // } else {
// // Logger.debug(TAG, 'aboutToAppear, data response page ' + this.pageId + ', comp list is empty.');
// // this.pageModel.viewType = ViewType.EMPTY;
// }
// }
// }
async getLiveListData(pageInfo: PageInfoBean) {
// Logger.info(TAG, `getData id: ${this.pageId} , ${this.channelId} , navIndex: ${this.currentTopNavSelectedIndex}`);
// this.pageModel.pageId = this.pageId;
// this.pageModel.groupId = this.pageId;
// this.pageModel.channelId = this.channelId;
// this.pageModel.currentPage = 1;
// let pageInfo = await PageViewModel.getPageUrlData(this.pageModel.pageId);
// if (pageInfo == null) {
// this.pageModel.viewType = ViewType.EMPTY;
// return;
// }
Logger.debug(TAG, 'getPageUrlData ' + pageInfo.id);
// pageInfo.groups.forEach(async (group) => { 不能按顺序加载用for...of替代
for (const group of pageInfo.groups) {
this.pageDto = await PageViewModel.getLivePageData(this.pageModel.pageId, `${group.id}`, this.pageModel.channelId, group.groupStrategy
, this.pageModel.currentPage, this.pageModel.pageSize, getContext(this))
this.pageModel.timestamp = DateTimeUtils.getTimeStamp().toString()
if (this.pageDto && this.pageDto.compList && this.pageDto.compList.length > 0) {
this.pageDto.compList.forEach((comp) => {
if (comp.compStyle === CompStyle.Zh_Grid_Layout_02 && this.liveReviewDTO && this.liveReviewDTO.list && this.liveReviewDTO.list.length > 0) {
comp.operDataList.push(...this.liveReviewDTO.list)
}
})
this.pageModel.viewType = ViewType.LOADED;
this.pageModel.compList.push(...this.pageDto.compList)
if (this.pageDto.compList.length === this.pageModel.pageSize) {
this.pageModel.currentPage++;
this.pageModel.hasMore = true;
} else {
this.pageModel.hasMore = false;
}
// 二次请求,批查互动数据
PageViewModel.getInteractData(this.pageDto.compList).then((data: CompDTO[]) => {
// 刷新,替换所有数据
this.pageModel.compList.replaceAll(...data)
this.pageModel.timestamp = DateTimeUtils.getTimeStamp().toString()
})
this.isFirstIn = false
} else {
Logger.debug(TAG, 'aboutToAppear, data response page ' + this.pageId + ', comp list is empty.');
this.pageModel.viewType = ViewType.EMPTY;
}
}
}
async getPreviewData() {
this.liveReviewDTO = await PageViewModel.getLiveReviewUrl(this.pageNum, this.pageModel.pageSize)
Logger.debug(TAG, 'aboutToAppear, getPreviewData ' + this.liveReviewDTO.hasNext);
this.getData();
this.pageModel.pageInfo = pageInfo;
this.pageModel.loadStrategy = 1
PageHelper.parseGroup(this.pageModel)
}
}
... ...
export class PageUIReqBean {
// 页面数据
pageId: string = '';
groupId: string = '';
channelId: string = '';
isRecGroup: boolean = false;
/**
* 首次加载:loadStrategy= 1
* 下拉刷新:loadStrategy= 2
* 上推刷新:loadStrategy= 3
*/
loadStrategy: number = 1;
currentPage: number = 1;
pageSize: number = 0;
/**
* 楼层类型:
* 推荐:1
* 普通:2
*/
groupStrategy: number = 2;
}
\ No newline at end of file
... ...
... ... @@ -23,6 +23,8 @@ import {
postInteractAccentionOperateParams,
postRecommendListParams
} from 'wdBean';
import { PageUIReqBean } from '../components/page/bean/PageUIReqBean';
import { LiveReviewDTO } from 'wdBean/src/main/ets/bean/component/LiveReviewDTO';
const TAG = 'HttpRequest';
... ... @@ -46,31 +48,70 @@ export class PageRepository {
return url;
}
static getCompInfoUrl(pageId: string, groupId: string, channelId: string, groupStrategy: number, currentPage: number, pageSize: number) {
let url = HttpUrlUtils.getHost();
if (1 == groupStrategy) {
//推荐
url = url + HttpUrlUtils.COMP_REC_PATH;
static getCompInfoUrl(pageBean: PageUIReqBean) {
let url = HttpUrlUtils.getHost() + HttpUrlUtils.COMP_PATH;
// first_load、pull_down、push_up
let loadStrategy = ''
if (pageBean.loadStrategy == 2) {
loadStrategy = 'pull_down'
} else if (pageBean.loadStrategy == 3) {
loadStrategy = 'push_up'
} else {
//非推荐
url = url + HttpUrlUtils.COMP_PATH;
loadStrategy = 'first_load'
}
// TODO 暂定只请求第一页,后续对接分页加载,参数再调整 first_load?
url = url + "?channelStrategy=2&loadStrategy=first_load"
url = url + "?channelStrategy=" + pageBean.groupStrategy
+ "&loadStrategy=" + loadStrategy
+ "&districtCode=" + HttpUrlUtils.getDistrictCode()
+ "&provinceCode=" + HttpUrlUtils.getProvinceCode()
+ "&cityCode=" + HttpUrlUtils.getCityCode()
+ "&refreshTime=" + DateTimeUtils.getTimeStamp()
+ "&pageId=" + pageId
+ "&groupId=" + groupId
+ "&channelId=" + channelId
+ "&pageSize=" + pageSize
+ "&pageNum=" + currentPage;
+ "&pageId=" + pageBean.pageId
+ "&groupId=" + pageBean.groupId
+ "&channelId=" + pageBean.channelId
+ "&pageSize=" + pageBean.pageSize
+ "&pageNum=" + pageBean.currentPage;
// Logger.debug("TAG", 'getCompInfoUrl url: '+url);
Logger.info(TAG, "getCompInfoUrl url = " + url)
return url;
}
static getRecCompInfoUrl(pageBean: PageUIReqBean) {
let url = HttpUrlUtils.getHost() + HttpUrlUtils.COMP_REC_PATH;
/**
* 首次加载:loadStrategy= first_load
* 上推刷新:loadStrategy= push_up
* 下拉刷新:loadStrategy= pull_down
*/
let loadStrategy = ''
if (pageBean.loadStrategy == 2) {
loadStrategy = 'pull_down'
} else if (pageBean.loadStrategy == 3) {
loadStrategy = 'push_up'
} else {
loadStrategy = 'first_load'
}
url = url + "?channelStrategy=" + pageBean.groupStrategy
+ "&loadStrategy=" + loadStrategy
+ "&districtCode=" + HttpUrlUtils.getDistrictCode()
+ "&provinceCode=" + HttpUrlUtils.getProvinceCode()
+ "&cityCode=" + HttpUrlUtils.getCityCode()
+ "&refreshTime=" + DateTimeUtils.getTimeStamp()
+ "&pageId=" + pageBean.pageId
+ "&groupId=" + pageBean.groupId
+ "&channelId=" + pageBean.channelId
+ "&pageSize=" + pageBean.pageSize
+ "&pageNum=" + pageBean.currentPage;
// Logger.debug("TAG", 'getCompInfoUrl url: '+url);
Logger.info(TAG, "getCompInfoUrl url = " + url)
return url;
}
static getLiveReviewUrl(pageNum: number = 1, pageSize: number = 20) {
let url = HttpUrlUtils.getHost() + HttpUrlUtils.LIVE_REVIEW_PATH + "?pageNum=" + pageNum + "&pageSize=" + pageSize;
Logger.info(TAG, "getLiveReviewUrl url = " + url)
return url;
}
static getDetailInfoUrl(relId: string, contentId: string, relType: string) {
let url = HttpUrlUtils.getHost() + HttpUrlUtils.DETAIL_PATH;
url = url + "?relId=" + relId
... ... @@ -194,14 +235,14 @@ export class PageRepository {
return WDHttp.get<ResponseDTO<PageInfoDTO>>(url, headers)
};
static fetchLivePageData(pageId: string, groupId: string, channelId: string, groupStrategy: number, currentPage: number, pageSize: number) {
let url = PageRepository.getCompInfoUrl(pageId, groupId, channelId, groupStrategy, currentPage, pageSize)
static fetchCompData(pageBean: PageUIReqBean) {
let url = PageRepository.getCompInfoUrl(pageBean)
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return WDHttp.get<ResponseDTO<PageDTO>>(url, headers)
};
static fetchCompData(pageId: string, groupId: string, channelId: string, groupStrategy: number, currentPage: number, pageSize: number) {
let url = PageRepository.getCompInfoUrl(pageId, groupId, channelId, groupStrategy, currentPage, pageSize)
static fetchRecCompData(pageBean: PageUIReqBean) {
let url = PageRepository.getRecCompInfoUrl(pageBean)
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return WDHttp.get<ResponseDTO<PageDTO>>(url, headers)
};
... ...
... ... @@ -5,6 +5,7 @@ import { PageDTO, CompDTO } from 'wdBean';
import PageModel from '../viewmodel/PageModel';
import PageViewModel from '../viewmodel/PageViewModel';
import { DateTimeUtils } from 'wdKit';
import PageHelper from '../viewmodel/PageHelper';
export function listTouchEvent(pageModel: PageModel, event: TouchEvent) {
switch (event.type) {
... ... @@ -71,31 +72,32 @@ export function touchUpPullRefresh(pageModel: PageModel) {
pageModel.currentPage = 1;
setTimeout(() => {
let self: PageModel = pageModel;
PageViewModel.getPageData(self, getContext())
.then((data: PageDTO) => {
self.timestamp = DateTimeUtils.getTimeStamp().toString()
if (data == null || data.compList == null || data.compList.length == 0) {
self.hasMore = false;
} else {
if (data.compList.length == self.pageSize) {
self.currentPage++;
self.hasMore = true;
} else {
self.hasMore = false;
}
// 刷新,替换所有数据
self.compList.replaceAll(...data.compList)
PageViewModel.getInteractData(data.compList).then((data: CompDTO[]) => {
// 刷新,替换所有数据
self.compList.replaceAll(...data)
self.timestamp = DateTimeUtils.getTimeStamp().toString()
})
}
closeRefresh(self, true);
}).catch((err: string | Resource) => {
promptAction.showToast({ message: err });
closeRefresh(self, false);
});
PageHelper.refreshUI(self)
// PageViewModel.getPageData(self.bizCopy(2))
// .then((data: PageDTO) => {
// self.timestamp = DateTimeUtils.getTimeStamp().toString()
// if (data == null || data.compList == null || data.compList.length == 0) {
// self.hasMore = false;
// } else {
// if (data.compList.length == self.pageSize) {
// self.currentPage++;
// self.hasMore = true;
// } else {
// self.hasMore = false;
// }
// // 刷新,替换所有数据
// self.compList.replaceAll(...data.compList)
// PageViewModel.getInteractData(data.compList).then((data: CompDTO[]) => {
// // 刷新,替换所有数据
// self.compList.replaceAll(...data)
// self.timestamp = DateTimeUtils.getTimeStamp().toString()
// })
// }
// closeRefresh(self, true);
// }).catch((err: string | Resource) => {
// promptAction.showToast({ message: err });
// closeRefresh(self, false);
// });
}, Const.DELAY_TIME);
} else {
closeRefresh(pageModel, false);
... ...
... ... @@ -2,8 +2,9 @@ import promptAction from '@ohos.promptAction';
import PageModel from '../viewmodel/PageModel';
import { RefreshConstants as Const } from './RefreshConstants';
import PageViewModel from '../viewmodel/PageViewModel';
import { PageDTO,CompDTO } from 'wdBean';
import { PageDTO, CompDTO } from 'wdBean';
import { DateTimeUtils } from 'wdKit';
import PageHelper from '../viewmodel/PageHelper';
export function touchMoveLoadMore(model: PageModel, event: TouchEvent) {
// list size +1
... ... @@ -28,29 +29,30 @@ export function touchUpLoadMore(model: PageModel) {
self.isLoading = true;
setTimeout(() => {
closeLoadMore(model);
PageViewModel.getPageData(self, getContext())
.then((data: PageDTO) => {
self.timestamp = DateTimeUtils.getTimeStamp().toString()
if (data == null || data.compList == null || data.compList.length == 0) {
self.hasMore = false;
} else {
if (data.compList.length == self.pageSize) {
self.currentPage++;
self.hasMore = true;
} else {
self.hasMore = false;
}
let sizeBefore:number = self.compList.size();
self.compList.push(...data.compList)
PageViewModel.getInteractData(data.compList).then((data: CompDTO[]) => {
// 刷新,替换所有数据
self.compList.updateItems(sizeBefore, data)
self.timestamp = DateTimeUtils.getTimeStamp().toString()
})
}
}).catch((err: string | Resource) => {
promptAction.showToast({ message: err });
})
PageHelper.loadMore(self)
// PageViewModel.getPageData(self.bizCopy())
// .then((data: PageDTO) => {
// self.timestamp = DateTimeUtils.getTimeStamp().toString()
// if (data == null || data.compList == null || data.compList.length == 0) {
// self.hasMore = false;
// } else {
// if (data.compList.length == self.pageSize) {
// self.currentPage++;
// self.hasMore = true;
// } else {
// self.hasMore = false;
// }
// let sizeBefore: number = self.compList.size();
// self.compList.push(...data.compList)
// PageViewModel.getInteractData(data.compList).then((data: CompDTO[]) => {
// // 刷新,替换所有数据
// self.compList.updateItems(sizeBefore, data)
// self.timestamp = DateTimeUtils.getTimeStamp().toString()
// })
// }
// }).catch((err: string | Resource) => {
// promptAction.showToast({ message: err });
// })
}, Const.DELAY_TIME);
} else {
closeLoadMore(self);
... ...
import { PageDTO, CompDTO, PageInfoDTO } from 'wdBean';
import { ViewType } from 'wdConstant/Index';
import { DateTimeUtils, Logger } from 'wdKit';
import { closeRefresh } from '../utils/PullDownRefresh';
import PageModel from './PageModel';
import PageViewModel from './PageViewModel';
import { promptAction } from '@kit.ArkUI';
const TAG = 'PageHelper';
/**
* 处理返回后的数据
* @deprecated
*/
export class PageHelper {
async refreshUI(pageModel: PageModel) {
pageModel.loadStrategy = 2
this.parseGroup(pageModel)
}
async loadMore(pageModel: PageModel) {
pageModel.loadStrategy = 3
// 暂只支持comp分页加载,节目分页加载的得完善框架(如直播回看节目数据分页)
this.compLoadMore(pageModel)
}
async parseGroup(pageModel: PageModel) {
let pageInfo: PageInfoDTO = pageModel.pageInfo
pageModel.groupList = []
pageModel.groupList.push(...pageInfo.groups)
for (const group of pageInfo.groups) {
pageModel.isRecGroup = group.groupStrategy === 1;
pageModel.groupId = group.id;
if (pageModel.isRecGroup) {
pageModel.pageSize = 10
} else {
pageModel.pageSize = 20
}
pageModel.groupData = group
// await,确保groups接口顺序执行
let pageDto = await PageViewModel.getPageData(pageModel.bizCopy())
let index = pageInfo.groups.indexOf(group)
if (index == 0) {
// 清空comp列表
pageModel.compList.clear()
}
this.getGroupData(pageModel, pageDto, index == pageInfo.groups.length - 1)
}
if (pageModel.compList.isEmpty()) {
// 没数据,展示空页面
Logger.debug(TAG, 'aboutToAppear, data response page ' + pageModel.pageId + ', comp list is empty.');
pageModel.viewType = ViewType.EMPTY;
}
}
private async getGroupData(pageModel: PageModel, pageDto: PageDTO, isLastGroup: boolean) {
pageModel.timestamp = DateTimeUtils.getTimeStamp().toString()
if (pageDto && pageDto.compList && pageDto.compList.length > 0) {
pageModel.viewType = ViewType.LOADED;
let sizeBefore: number = pageModel.compList.size();
pageModel.compList.push(...pageDto.compList)
if (pageDto.compList.length === pageModel.pageSize) {
pageModel.currentPage++;
pageModel.hasMore = true;
} else {
pageModel.hasMore = false;
}
// 二次请求,批查互动数据
PageViewModel.getInteractData(pageDto.compList).then((data: CompDTO[]) => {
// 刷新,替换所有数据
// pageModel.compList.replaceAll(...data)
pageModel.compList.updateItems(sizeBefore, data)
pageModel.timestamp = DateTimeUtils.getTimeStamp().toString()
})
// TODO 待优化,解决content级别的展现加载
if (isLastGroup) {
closeRefresh(pageModel, true);
// // 最后一个楼层,特殊处理
// // 检测楼层最后一个组件业务数据是否需要通过访问接口获取
// let comp: CompDTO = pageDto.compList[pageDto.compList.length - 1]
// let compSize = CollectionUtils.getListSize(comp.operDataList)
// // 直播回放,需要二次请求数据
// if (compSize <= 0 && comp.dataSourceType == 'LIVE_END') {
// let liveReviewDTO = await PageViewModel.getLiveReviewUrl(pageModel.currentPage, pageModel.pageSize)
// // content数据回来,塞给comp
// comp.operDataList.push(...liveReviewDTO.list)
// }
}
}
}
/**
* 获取直播回看数据
*/
private async getLiveEnd(pageModel: PageModel) {
let liveReviewDTO = await PageViewModel.getLiveReviewUrl(pageModel.currentPage, pageModel.pageSize)
Logger.debug(TAG, 'aboutToAppear, getPreviewData ' + liveReviewDTO.hasNext);
}
/**
* comp加载更多,分页加载
*/
private compLoadMore(pageModel: PageModel) {
PageViewModel.getPageData(pageModel.bizCopy())
.then((data: PageDTO) => {
pageModel.timestamp = DateTimeUtils.getTimeStamp().toString()
if (data == null || data.compList == null || data.compList.length == 0) {
pageModel.hasMore = false;
} else {
if (data.compList.length == pageModel.pageSize) {
pageModel.currentPage++;
pageModel.hasMore = true;
} else {
pageModel.hasMore = false;
}
let sizeBefore: number = pageModel.compList.size();
pageModel.compList.push(...data.compList)
PageViewModel.getInteractData(data.compList).then((data: CompDTO[]) => {
// 刷新,替换所有数据
pageModel.compList.updateItems(sizeBefore, data)
pageModel.timestamp = DateTimeUtils.getTimeStamp().toString()
})
}
}).catch((err: string | Resource) => {
promptAction.showToast({ message: err });
})
}
/**
* 节目数据分页加载
* TODO 待完善框架
*/
private contentLoadMore() {
}
}
let pageHelper = new PageHelper();
export default pageHelper as PageHelper;
\ No newline at end of file
... ...
import { CompDTO } from 'wdBean';
import { CompDTO, GroupDTO } from 'wdBean';
import { LazyDataSource } from 'wdKit';
import { ViewType } from 'wdConstant/src/main/ets/enum/ViewType';
import { RefreshConstants as Const } from '../utils/RefreshConstants';
import { PageUIReqBean } from '../components/page/bean/PageUIReqBean';
import { GroupInfoDTO, PageInfoDTO } from 'wdBean/src/main/ets/bean/navigation/PageInfoDTO';
/**
* 页面下拉刷新、上拉加载数据bean。
* TODO 将业务数据拆出去
*/
export default class PageModel {
// 页面数据
pageId: string = "";
groupId: string = "";
channelId: string = "";
isRecGroup: boolean = false;
pageInfo: PageInfoDTO = {} as PageInfoDTO
groupList: GroupInfoDTO[] = [];
// 当前请求数据的group
groupData: GroupInfoDTO = {} as GroupInfoDTO;
compList: LazyDataSource<CompDTO> = new LazyDataSource();
// 页面状态,刷新、加载更多等
// 页面状态,刷新、加载更多等,1-首次、2-下拉、3上拉
loadStrategy: number = 1;
currentPage: number = 1;
pageSize: number = Const.PAGE_SIZE;
pullDownRefreshText: Resource = $r('app.string.pull_down_refresh_text');
... ... @@ -35,5 +46,20 @@ export default class PageModel {
isCanLoadMore: boolean = false;
// keyGenerator相关字符串,用于刷新list布局
timestamp: String = '1';
groupStrategy: number = 0;
}
\ No newline at end of file
/**
* 简单复制业务数据
*/
bizCopy(): PageUIReqBean {
let page = new PageUIReqBean()
page.pageId = this.pageId
page.groupId = this.groupId
page.channelId = this.channelId
page.isRecGroup = this.isRecGroup
page.currentPage = this.currentPage
page.pageSize = this.pageSize
page.groupStrategy = this.groupData.groupStrategy
page.loadStrategy = this.loadStrategy
return page
}
}
... ...
... ... @@ -10,8 +10,10 @@ import {
PageInfoBean
} from 'wdBean';
import { LiveReviewDTO } from 'wdBean/src/main/ets/bean/component/LiveReviewDTO';
import { CollectionUtils, Logger, ResourcesUtils, StringUtils } from 'wdKit';
import { ResponseDTO, } from 'wdNetwork';
import { PageUIReqBean } from '../components/page/bean/PageUIReqBean';
import { PageRepository } from '../repository/PageRepository';
import { BaseViewModel } from './BaseViewModel';
import PageModel from './PageModel';
... ... @@ -141,16 +143,12 @@ export class PageViewModel extends BaseViewModel {
return compRes.data
}
async getPageData(pageModel: PageModel, context?: Context): Promise<PageDTO> {
async getPageData(pageModel: PageUIReqBean): Promise<PageDTO> {
Logger.debug(TAG, 'getPageData pageId: ' + pageModel.pageId);
return this.parseComp(PageRepository.fetchCompData(pageModel.pageId, pageModel.groupId, pageModel.channelId, pageModel.isRecGroup == true ? 1 : 0, pageModel.currentPage, pageModel.pageSize))
}
async getLivePageData(pageId: string, groupId: string, channelId: string, groupStrategy: number, currentPage: number
, pageSize: number, context: Context): Promise<PageDTO> {
Logger.debug(TAG, 'getPageData pageId: ' + pageId);
if (mock_switch) {
return this.getPageData1(currentPage, context);
if (pageModel.isRecGroup) {
return this.parseComp(PageRepository.fetchRecCompData(pageModel))
} else {
return this.parseComp(PageRepository.fetchCompData(pageModel))
}
return new Promise<PageDTO>((success, error) => {
PageRepository.fetchLivePageData(pageId, groupId, channelId, groupStrategy, currentPage, pageSize)
... ... @@ -365,6 +363,30 @@ export class PageViewModel extends BaseViewModel {
})
})
}
async getLiveReviewUrl(pageNum: number, pageSize: number): Promise<LiveReviewDTO> {
return new Promise<LiveReviewDTO>((success, error) => {
Logger.info(TAG, `getLivePreviewUrl pageInfo start`);
PageRepository.fetchLiveReviewUrl(pageNum, pageSize).then((resDTO: ResponseDTO<LiveReviewDTO>) => {
if (!resDTO || !resDTO.data) {
Logger.error(TAG, 'getLivePreviewUrl then navResDTO is empty');
error('resDTO is empty');
return
}
if (resDTO.code != 0) {
Logger.error(TAG, `getLivePreviewUrl then code:${resDTO.code}, message:${resDTO.message}`);
error('resDTO Response Code is failure');
return
}
// let navResStr = JSON.stringify(navResDTO);
Logger.info(TAG, "getLivePreviewUrl then,navResDTO.timestamp:" + resDTO.timestamp);
success(resDTO.data);
}).catch((err: Error) => {
Logger.error(TAG, `getLivePreviewUrl catch, error.name : ${err.name}, error.message:${err.message}`);
error(err);
})
})
}
}
... ...
... ... @@ -12,6 +12,7 @@
"wdNetwork": "file:../../commons/wdNetwork",
"wdKit": "file:../../commons/wdKit",
"wdBean": "file:../../features/wdBean",
"wdConstant": "file:../../commons/wdConstant"
"wdConstant": "file:../../commons/wdConstant",
"wdDetailPlayApi": "file:../../features/wdDetailPlayApi"
}
}
... ...
import { LiveDetailsBean } from 'wdBean/Index';
import { Action, LiveDetailsBean, LiveRoomDataBean } from 'wdBean/Index';
import { LiveViewModel } from '../viewModel/LiveViewModel';
import { BottomComponent } from '../widgets/details/BottomComponent';
import { TabComponent } from '../widgets/details/TabComponent';
import { TopPlayComponent } from '../widgets/details/video/TopPlayComponet';
import router from '@ohos.router';
@Entry
@Component
export struct DetailPlayLivePage {
TAG: string = 'DetailPlayLivePage';
liveViewModel: LiveViewModel = new LiveViewModel()
@State relId: string = ''
@State contentId: string = ''
@State relType: string = ''
@Provide liveDetailsBean: LiveDetailsBean = {} as LiveDetailsBean
@Provide liveRoomDataBean: LiveRoomDataBean = {} as LiveRoomDataBean
aboutToAppear(): void {
let par: Action = router.getParams() as Action;
let params = par?.params;
this.relId = params?.extra?.relId || '';
this.relType = params?.extra?.relType || '';
this.contentId = params?.contentID || '';
this.getLiveDetails()
this.getLiveRoomData()
}
build() {
Column() {
TopPlayComponent({playUrl:'http://mlive3.video.weibocdn.com/record/alicdn/5018726527666338/index.m3u8'})
TopPlayComponent()
TabComponent()
BottomComponent()
}
... ... @@ -30,8 +41,7 @@ export struct DetailPlayLivePage {
}
getLiveDetails() {
this.liveViewModel.getLiveDetails('20000016333', '500005300349', '1')//2024-04-12 15:00:00
// this.liveViewModel.getLiveDetails('20000016229', '500005272745', '1')//2024-04-03 05:00:00
this.liveViewModel.getLiveDetails(this.contentId, this.relId, this.relType)
.then(
(data) => {
if (data.length > 0) {
... ... @@ -43,6 +53,17 @@ export struct DetailPlayLivePage {
})
}
getLiveRoomData() {
this.liveViewModel.getLiveRoomData(this.contentId)
.then(
(data) => {
this.liveRoomDataBean = data
},
() => {
})
}
aboutToDisappear(): void {
}
... ...
import HashMap from '@ohos.util.HashMap';
import { HttpUrlUtils, ResponseDTO } from 'wdNetwork';
import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest';
import { Logger } from 'wdKit';
import { LiveDetailsBean, LiveRoomBean } from 'wdBean/Index';
import { Logger, ToastUtils } from 'wdKit';
import { LiveDetailsBean, LiveRoomBean, LiveRoomDataBean } from 'wdBean/Index';
const TAG = 'LiveModel'
... ... @@ -107,5 +107,91 @@ export class LiveModel {
})
})
}
/**
* 获取直播数据
* @param liveId
* @returns
*/
getLiveRoomData(liveId: string) {
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return new Promise<LiveRoomDataBean>((success, fail) => {
HttpRequest.get<ResponseDTO<LiveRoomDataBean>>(
HttpUrlUtils.getLiveRoomDataUrl() + `?liveId=${liveId}`,
headers).then((data: ResponseDTO<LiveRoomDataBean>) => {
if (!data || !data.data) {
fail("数据为空")
return
}
if (data.code != 0) {
fail(data.message)
return
}
success(data.data)
}, (error: Error) => {
fail(error.message)
Logger.debug(TAG + ":error ", error.toString())
})
})
}
/**
* 获取直播预约状态
* @param relationId
* @param liveId
* @returns
*/
getLiveAppointmentStatus(relationId: string, liveId: string) {
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return new Promise<boolean>((success, fail) => {
HttpRequest.get<ResponseDTO<boolean>>(
HttpUrlUtils.getLiveAppointmentStatusUrl() + `?relationId=${relationId}&liveId=${liveId}`,
headers).then((data: ResponseDTO<boolean>) => {
if (!data || !data.data) {
fail("数据为空")
return
}
if (data.code != 0) {
fail(data.message)
return
}
success(data.data)
}, (error: Error) => {
fail(error.message)
Logger.debug(TAG + ":error ", error.toString())
})
})
}
/**
* 直播预约/取消预约
* @param relationId
* @param mLiveId
* @param isSubscribe
* @returns
*/
liveAppointment(relationId: string, mLiveId: string, isSubscribe: boolean) {
let params: Record<string, string> = {};
params['relationId'] = relationId
params['liveId'] = mLiveId
params['isSubscribe'] = `${isSubscribe}`
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return new Promise<ResponseDTO<string>>((success, fail) => {
HttpRequest.post<ResponseDTO<string>>(
HttpUrlUtils.getLiveAppointmentUrl(),
params,
headers).then((data: ResponseDTO<string>) => {
if (data.code != 0) {
fail(data.message)
ToastUtils.shortToast(data.message)
return
}
success(data)
}, (error: Error) => {
fail(error.message)
Logger.debug(TAG + ":error ", error.toString())
})
})
}
}
... ...
import { LiveDetailsBean, LiveRoomBean } from 'wdBean/Index'
import { LiveDetailsBean, LiveRoomBean, LiveRoomDataBean } from 'wdBean/Index'
import { ResponseDTO } from 'wdNetwork/Index'
import { LiveModel } from './LiveModel'
const TAG = "LiveViewModel"
... ... @@ -42,4 +43,37 @@ export class LiveViewModel {
})
})
}
//直播详情直播间数据
getLiveRoomData(liveId: string) {
return new Promise<LiveRoomDataBean>((success, fail) => {
this.liveModel.getLiveRoomData(liveId).then((data) => {
success(data)
}).catch((message: string) => {
fail(message)
})
})
}
//直播预约状态查询
getLiveAppointmentStatus(relationId: string, liveId: string) {
return new Promise<boolean>((success, fail) => {
this.liveModel.getLiveAppointmentStatus(relationId, liveId).then((data) => {
success(data)
}).catch((message: string) => {
fail(message)
})
})
}
//直播预约/取消预约
liveAppointment(relationId: string, mLiveId: string, isSubscribe: boolean) {
return new Promise<ResponseDTO<string>>((success, fail) => {
this.liveModel.liveAppointment(relationId, mLiveId, isSubscribe).then((data) => {
success(data)
}).catch((message: string) => {
fail(message)
})
})
}
}
\ No newline at end of file
... ...
import font from '@ohos.font'
import { LiveDetailsBean } from 'wdBean/Index'
import { DateTimeUtils, StringUtils } from 'wdKit/Index'
import { LiveViewModel } from '../../viewModel/LiveViewModel'
@Component
export struct LiveCountdownComponent {
... ... @@ -13,6 +14,9 @@ export struct LiveCountdownComponent {
@State minute: string = ''
@State differenceTimeStamp: number = 0
@State isCountDownStart: boolean = false
//是否预约过直播
@State isAppointmentLive: boolean = false
liveViewModel: LiveViewModel = new LiveViewModel()
aboutToAppear(): void {
//注册字体
... ... @@ -107,15 +111,23 @@ export struct LiveCountdownComponent {
top: 16
})
.border({ radius: 4 })
.backgroundColor('#ED2800')
// .backgroundColor('#CCCCCC')
.backgroundColor(this.isAppointmentLive ? '#CCCCCC' : '#ED2800')
.onClick(() => {
if (this.liveDetailsBean && this.liveDetailsBean.liveInfo) {
this.liveAppointment()
}
})
}
calculateDataStatus() {
if (!this.liveDetailsBean) {
return
}
this.getLiveAppointmentStatus()
let startTimeStamp: number = DateTimeUtils.getDateTimestamp(this.liveDetailsBean.liveInfo.planStartTime)
let currentTimeStamp: number = DateTimeUtils.getTimeStamp()
let _differenceTimeStampTmp = startTimeStamp - currentTimeStamp
this.isCountDownStart = _differenceTimeStampTmp <= 4 * 60 * 60 * 1000
this.isCountDownStart = _differenceTimeStampTmp <= 0 ? false : _differenceTimeStampTmp <= 4 * 60 * 60 * 1000
if (this.isCountDownStart) {
this.differenceTimeStamp = _differenceTimeStampTmp
return
... ... @@ -129,6 +141,34 @@ export struct LiveCountdownComponent {
this.minute = playStartTimeTmp.substring(14, 16)
}
}
getLiveAppointmentStatus() {
this.liveViewModel.getLiveAppointmentStatus(
this.liveDetailsBean.reLInfo ? this.liveDetailsBean.reLInfo.relId : '',
this.liveDetailsBean.newsId
).then(
(data) => {
this.isAppointmentLive = data
},
() => {
})
}
liveAppointment() {
this.liveViewModel.liveAppointment(
this.liveDetailsBean.reLInfo ? this.liveDetailsBean.reLInfo.relId : '',
this.liveDetailsBean.newsId,
!this.isAppointmentLive).then(
(data) => {
if (data.success) {
this.isAppointmentLive = !this.isAppointmentLive
}
},
() => {
})
}
}
@Extend(Text)
... ...
import { LiveRoomItemBean } from 'wdBean/Index'
import { LiveDetailsBean, LiveRoomItemBean } from 'wdBean/Index'
import { ListHasNoMoreDataUI } from 'wdComponent/Index'
import { StringUtils } from 'wdKit/Index'
import { LiveViewModel } from '../../viewModel/LiveViewModel'
import { TabLiveItemComponent } from './TabLiveItemComponent'
... ... @@ -7,6 +8,7 @@ import { TabLiveItemComponent } from './TabLiveItemComponent'
export struct TabLiveComponent {
liveViewModel: LiveViewModel = new LiveViewModel()
@State liveList: Array<LiveRoomItemBean> = []
@Consume liveDetailsBean: LiveDetailsBean
aboutToAppear(): void {
this.getLiveList()
... ... @@ -40,6 +42,20 @@ export struct TabLiveComponent {
this.liveViewModel.getLiveList(1, '20000016257', '20000016229', 20,)
.then(
(data) => {
/**
* 在直播聊天添加一条新内容逻辑:
判断 oldNewsId:迁移id非空 且 直播状态不是预约:"wait"
消息内容:
1.头像固定:APP默认头像
2.名称固定:人民日报主持人
3.内容:详情接口的简介,newIntroduction
*/
if (StringUtils.isNotEmpty(this.liveDetailsBean.oldNewsId) && this.liveDetailsBean && this.liveDetailsBean.liveInfo.liveState != 'wait') {
let liveRoomItemBeanTemp: LiveRoomItemBean = {} as LiveRoomItemBean
liveRoomItemBeanTemp.text = this.liveDetailsBean.newIntroduction
liveRoomItemBeanTemp.senderUserName = '人民日报主持人'
data.barrageResponses.push(liveRoomItemBeanTemp)
}
this.liveList = data.barrageResponses
},
() => {
... ...
import { LiveRoomItemBean } from 'wdBean/Index'
import { DateTimeUtils } from 'wdKit/Index'
import { DateTimeUtils, StringUtils } from 'wdKit/Index'
@Component
export struct TabLiveItemComponent {
... ... @@ -12,7 +12,7 @@ export struct TabLiveItemComponent {
build() {
Column() {
Row() {
Image(this.item.senderUserAvatarUrl)
Image(StringUtils.isEmpty(this.item.senderUserAvatarUrl) ? $r('app.media.default_head') : this.item.senderUserAvatarUrl)
.borderRadius(90)
.width(24)
.height(24)
... ... @@ -46,6 +46,7 @@ export struct TabLiveItemComponent {
.fontWeight(400)
.fontColor('#999999')
.margin({ left: 8 })
.visibility(StringUtils.isNotEmpty(this.item.time) ? Visibility.Visible : Visibility.None)
Blank()
Text('置顶')
.maxLines(1)
... ...
import { window } from '@kit.ArkUI'
import { DateTimeUtils, NumberFormatterUtils, WindowModel } from 'wdKit/Index'
import { devicePLSensorManager } from 'wdDetailPlayApi/Index'
import { LiveDetailsBean, LiveRoomDataBean } from 'wdBean/Index'
import { WDPlayerController } from 'wdPlayer/Index'
@Entry
@Component
export struct PlayUIComponent {
playerController: WDPlayerController = new WDPlayerController();
//菜单键是否可见
@State isMenuVisible: boolean = true
@State isFullScreen: boolean = false
@Consume liveDetailsBean: LiveDetailsBean
@Consume liveRoomDataBean: LiveRoomDataBean
@State currentTime: string = ''
@State totalTime: string = ''
@State progressVal: number = 0;
//是否处于播放状态中
@State isPlayStatus: boolean = true
aboutToAppear(): void {
//播放进度监听
this.playerController.onTimeUpdate = (position: number, duration: number) => {
this.currentTime = DateTimeUtils.secondToTime(position);
this.totalTime = DateTimeUtils.secondToTime(duration);
this.progressVal = Math.floor(position * 100 / duration);
}
}
build() {
Column() {
this.getTopUIComponent()
this.getMiddleUIComponent()
this.getBottomUIComponent()
}
.width('100%')
.height('100%')
.alignItems(HorizontalAlign.Start)
}
@Builder
getTopUIComponent() {
Column() {
Row() {
Image($r('app.media.icon_arrow_left_white'))
.width(24)
.aspectRatio(1)
.visibility(Visibility.None)
.margin({
right: 10
})
Text(this.liveDetailsBean.newsTitle)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontSize('16fp')
.fontWeight(500)
.fontColor(Color.White)
.textAlign(TextAlign.Start)
.layoutWeight(1)
Image($r('app.media.icon_share'))
.width(24)
.aspectRatio(1)
.visibility(Visibility.None)
}
.width('100%')
.alignItems(VerticalAlign.Center)
.margin({
bottom: 5
})
this.getLiveStatusView()
}.width('100%')
.padding({
top: 10,
bottom: 6,
left: 10,
right: 10
})
.alignItems(HorizontalAlign.Start)
.visibility(this.isMenuVisible ? Visibility.Visible : Visibility.None)
}
@Builder
getLiveStatusView() {
//预约
//直播中
//回看
Row() {
Text('回看')
.fontSize('11fp')
.fontWeight(400)
.fontColor(Color.White)
Image($r('app.media.icon_live_player_status_end'))
.width(12)
.height(12)
Text(`${NumberFormatterUtils.formatNumberWithWan(this.liveRoomDataBean.pv)}人参与`)
.fontSize('11fp')
.fontWeight(400)
.fontColor(Color.White)
}
.backgroundColor('#4D000000')
.padding({
left: 4,
top: 1,
right: 4,
bottom: 1
})
}
@Builder
getMiddleUIComponent() {
Stack()
.layoutWeight(1)
.width('100%')
.onClick(() => {
this.isMenuVisible = !this.isMenuVisible
})
}
@Builder
getBottomUIComponent() {
Row() {
this.playOrPauseBtn()
Text(this.currentTime)
.fontColor(Color.White)
.fontWeight(600)
.fontSize('12fp')
.margin({
left: 16
})
this.playProgressView()
Text(this.totalTime)
.fontColor(Color.White)
.fontWeight(600)
.fontSize('12fp')
.margin({
right: 16
})
Image($r('app.media.icon_live_player_full_screen'))
.width(24)
.height(24)
.onClick(() => {
this.isFullScreen = !this.isFullScreen
WindowModel.shared.setPreferredOrientation(this.isFullScreen ? window.Orientation.LANDSCAPE : window.Orientation.PORTRAIT);
devicePLSensorManager.devicePLSensorOn(this.isFullScreen ? window.Orientation.LANDSCAPE : window.Orientation.PORTRAIT);
})
}
.alignItems(VerticalAlign.Center)
.linearGradient({ angle: 0, colors: [['#99000000', 0], ['#00000000', 1]] })
.width('100%')
.padding({
left: 10,
right: 10,
top: 15,
bottom: 15
})
.visibility(this.isMenuVisible ? Visibility.Visible : Visibility.None)
}
@Builder
playOrPauseBtn() {
//暂停、播放
Image(this.isPlayStatus ? $r('app.media.icon_live_player_pause') : $r('app.media.player_play_ic'))
.width(24)
.height(24)
.onClick(() => {
if (this.isPlayStatus) {
this.isPlayStatus = false
this.playerController.pause()
} else {
this.isPlayStatus = true
this.playerController.play()
}
})
}
@Builder
playProgressView() {
Slider({
value: this.progressVal,
step: 1,
// style: SliderStyle.OutSet
})
.blockStyle({
type: SliderBlockType.IMAGE,
image: $r('app.media.ic_player_block')
})
.blockColor(Color.White)
.trackColor('#4DFFFFFF')
.selectedColor('#FFED2800')
.height(2)
.trackThickness(1)
.layoutWeight(1)
.margin({
left: 8,
right: 8
})
.onChange((value: number, mode: SliderChangeMode) => {
this.playerController?.setSeekTime(value, mode);
})
}
}
\ No newline at end of file
... ...
import { WDPlayerController, WDPlayerRenderView } from 'wdPlayer/Index';
import { LiveDetailsBean } from 'wdBean/Index';
import { WDPlayerController, WDPlayerRenderLiveView } from 'wdPlayer/Index';
import { PlayUIComponent } from './PlayUIComponent';
@Component
export struct TopPlayComponent {
@Prop playUrl: string=''
aspectRatioPlayer: number = 375 / 211
@State playerController: WDPlayerController = new WDPlayerController();
@Consume @Watch('updateData') liveDetailsBean: LiveDetailsBean
playerController: WDPlayerController = new WDPlayerController();
aboutToAppear(): void {
setTimeout(() => {
this.playerController.switchPlayOrPause()
},2000)
this.playerController.onCanplay = () => {
this.playerController.play()
}
}
updateData() {
if (this.liveDetailsBean.liveInfo && this.liveDetailsBean.liveInfo.vlive.length > 0) {
let playUrl: string = this.liveDetailsBean.liveInfo.vlive[0].replayUri
this.playerController.firstPlay(playUrl);
}
}
build() {
Stack() {
WDPlayerRenderView({
WDPlayerRenderLiveView({
playerController: this.playerController,
onLoad: async () => {
this.playerController.firstPlay(this.playUrl);
}
})
.height('100%')
.width('100%')
.onClick(() => {
console.error('WDPlayerRenderView=== onClick')
this.playerController?.switchPlayOrPause();
})
PlayUIComponent({ playerController: this.playerController })
}
.height(211)
.aspectRatio(this.aspectRatioPlayer)
.backgroundColor(Color.Black)
.width('100%')
}
aboutToDisappear(): void {
this.playerController.pause()
}
}
\ No newline at end of file
... ...
... ... @@ -9,6 +9,11 @@
"2in1"
],
"deliveryWithInstall": true,
"pages": "$profile:main_pages"
"pages": "$profile:main_pages",
"requestPermissions": [
{
"name":"ohos.permission.ACCELEROMETER"
}
]
}
}
\ No newline at end of file
... ...
... ... @@ -2,6 +2,8 @@ export { WDPlayerController } from "./src/main/ets/controller/WDPlayerController
export { WDPlayerRenderView } from "./src/main/ets/pages/WDPlayerRenderView"
export { WDPlayerRenderLiveView } from "./src/main/ets/pages/WDPlayerRenderLiveView"
export { PlayerConstants } from "./src/main/ets/constants/PlayerConstants"
export { SpeedBean } from "./src/main/ets/bean/SpeedBean"
... ...
import componentUtils from '@ohos.arkui.componentUtils';
import { WDPlayerController } from '../controller/WDPlayerController'
import { WindowModel } from 'wdKit';
import { Logger } from '../utils/Logger';
class Size {
width: Length = "100%";
height: Length = "100%";
constructor(width: Length, height: Length) {
this.width = width;
this.height = height;
}
}
let insIndex: number = 0;
const TAG = 'WDPlayerRenderLiveView'
class MGPlayRenderViewIns {
static intCount: number = 0;
static add() {
MGPlayRenderViewIns.intCount++;
WindowModel.shared.setWindowKeepScreenOn(true);
console.log("add-- +1")
}
static del() {
console.log("del-- -1")
MGPlayRenderViewIns.intCount--;
if (MGPlayRenderViewIns.intCount <= 0) {
WindowModel.shared.setWindowKeepScreenOn(false);
}
}
}
/**
* 播放窗口组件
*/
@Component
export struct WDPlayerRenderLiveView {
private playerController?: WDPlayerController;
private xComponentController: XComponentController = new XComponentController();
onLoad?: ((event?: object) => void);
videoWidth: number = 0
videoHeight: number = 0
@State selfSize: Size = new Size('100%', '100%');
private insId: string = "WDPlayRenderView" + insIndex;
aboutToAppear() {
MGPlayRenderViewIns.add();
console.log('playerController', this.playerController)
insIndex++;
if (!this.playerController) {
return
}
this.playerController.onVideoSizeChange = (width: number, height: number) => {
// console.log(`WDPlayerRenderView onVideoSizeChange width:${width} videoTop:${height}`)
Logger.info(TAG, ` onVideoSizeChange width:${width} videoTop:${height}`)
this.videoWidth = width;
this.videoHeight = height;
this.updateLayout()
}
}
aboutToDisappear() {
Logger.info(TAG, `aboutToDisappear`)
MGPlayRenderViewIns.del();
}
build() {
Row() {
// 设置为“surface“类型时XComponent组件可以和其他组件一起进行布局和渲染。
XComponent({
id: 'xComponentId',
type: 'surface',
controller: this.xComponentController
})
.onLoad(async (event) => {
Logger.info(TAG, 'onLoad')
let surfaceId = this.xComponentController.getXComponentSurfaceId()
console.log('surfaceId===', surfaceId)
console.log('insId===', this.insId)
this.xComponentController.setXComponentSurfaceSize({
surfaceWidth: 1920,
surfaceHeight: 1080
});
this.playerController?.setXComponentController(this.xComponentController)
if (this.onLoad) {
this.onLoad(event)
}
})
.width(this.selfSize.width)
.height(this.selfSize.height)
}
.id(this.insId)
.onAreaChange(() => {
// this.updateLayout()
})
.backgroundColor("#000000")
.justifyContent(FlexAlign.Center)
.height('100%')
.width('100%')
}
updateLayout() {
let info = componentUtils.getRectangleById(this.insId);
if (info.size.width > 0 && info.size.height > 0 && this.videoHeight > 0 && this.videoWidth > 0) {
if (info.size.width / info.size.height > this.videoWidth / this.videoHeight) {
let scale = info.size.height / this.videoHeight;
this.selfSize = new Size((this.videoWidth * scale / info.size.width) * 100 + "%", '100%');
} else {
let scale = info.size.width / this.videoWidth;
this.selfSize = new Size('100%', (this.videoHeight * scale / info.size.height) * 100 + "%");
}
}
}
}
\ No newline at end of file
... ...