yumaochao

Merge remote-tracking branch 'origin/main'

Showing 30 changed files with 1007 additions and 58 deletions
... ... @@ -26,6 +26,7 @@ export class Size {
export class WindowModel {
private windowStage?: window.WindowStage;
private windowClass?: window.Window;
private isFullScreen: boolean = false
static shared: WindowModel = new WindowModel()
static TAG = "WindowModel";
... ... @@ -129,7 +130,15 @@ export class WindowModel {
this.windowClass?.setWindowSystemBarProperties(systemBarProperties, (err: BusinessError) => {
callback && callback(err)
})
}
setWindowLayoutFullScreen(isFullScreen: boolean) {
this.isFullScreen = isFullScreen
this.windowClass?.setWindowLayoutFullScreen(isFullScreen)
}
getIsFullScreen(): boolean {
return this.isFullScreen
}
}
... ...
... ... @@ -8,6 +8,7 @@
"version": "1.0.0",
"dependencies": {
"wdKit": "file:../wdKit",
"wdBean": "file:../../features/wdBean"
"wdBean": "file:../../features/wdBean",
"wdNetwork": "file:../../commons/wdNetwork"
}
}
\ No newline at end of file
... ...
... ... @@ -50,13 +50,17 @@ export function registerRouter() {
Action2Page.register("JUMP_DETAIL_PAGE", (action: Action) => {
if (action.params?.detailPageType == 2 || action.params?.detailPageType == 6) {
if (action.params?.liveStyle === 0) {
return WDRouterPage.detailPlayLivePage
} else {
return WDRouterPage.detailPlayVLivePage
}
} else if (action.params?.detailPageType == 7 || action.params?.detailPageType == 8) {
return WDRouterPage.detailVideoListPage
}else if(action.params?.detailPageType == 9){
} else if (action.params?.detailPageType == 9) {
//图集详情页
return WDRouterPage.multiPictureDetailPage
}else if(action.params?.detailPageType == 14 || action.params?.detailPageType == 15){
} else if (action.params?.detailPageType == 14 || action.params?.detailPageType == 15) {
//动态详情页
return WDRouterPage.dynamicDetailPage
} else if (action.params?.detailPageType == 17) {
... ...
... ... @@ -14,6 +14,16 @@ export class WDRouterPage {
return `@bundle:${bundleInfo.name}/${"phone"}/${"ets/pages/MainPage"}`
}
static getLoginBundleInfo() {
let bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT)
return `@bundle:${bundleInfo.name}/${"wdLogin"}/${"ets/pages/login/LoginPage"}`
}
static getSettingBundleInfo() {
let bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT)
return `@bundle:${bundleInfo.name}/${"wdComponent"}/${"ets/components/page/SettingPage"}`
}
url() {
let bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT)
... ...
... ... @@ -12,4 +12,5 @@ export interface ExtraDTO extends ItemDTO {
sourcePage: string;
relId: string;
relType: string;
liveStreamType?: number
}
\ No newline at end of file
... ...
... ... @@ -18,5 +18,6 @@ export interface Params {
// 8.专辑竖屏详情页
// 13.音频详情页
// 17.多图(图集)详情页
detailPageType?:number; // 详情页类型
detailPageType?: number; // 详情页类型
liveStyle?: number; // 直播类型:0横屏,1竖屏
}
... ...
... ... @@ -164,6 +164,7 @@ export interface LiveDetailsBean {
//迁移id
oldNewsId: string
reLInfo: ReLInfo
rmhInfo: RmhInfo
}
export interface LiveInfo {
... ... @@ -189,8 +190,18 @@ export interface Vlive {
liveUrl: string
//直播回看地址,多路直播录制文件URL
replayUri: string
// 画面兼容 0-横屏流画面,1-竖屏流画面(仅竖屏直播使用)【前端使用, 可能竖屏模式但是直播流画面是横屏流,前端使用该字段】
liveStreamType: number | null
}
export interface ReLInfo {
relId: string
}
export interface RmhInfo {
rmhName: string;
rmhHeadUrl: string;
rmhId: string;
userId: string;
userType: string;
}
\ No newline at end of file
... ...
... ... @@ -4,6 +4,7 @@ import { Logger } from 'wdKit';
import { StringUtils } from 'wdKit/src/main/ets/utils/StringUtils';
import { WDRouterRule } from 'wdRouter';
import { ContentConstants } from '../constants/ContentConstants';
import { LiveModel } from '../viewmodel/LiveModel';
const TAG = 'ProcessUtils';
... ... @@ -71,7 +72,7 @@ export class ProcessUtils {
params: {
detailPageType: 14,
contentID: content?.objectId,
extra:{
extra: {
relType: content?.relType,
relId: content?.relId,
} as ExtraDTO
... ... @@ -91,7 +92,7 @@ export class ProcessUtils {
params: {
detailPageType: 17,
contentID: content?.objectId,
extra:{
extra: {
relType: content?.relType,
relId: content?.relId,
} as ExtraDTO
... ... @@ -111,6 +112,7 @@ export class ProcessUtils {
};
WDRouterRule.jumpWithAction(taskAction)
}
private static gotoWeb(content: ContentDTO) {
// // topicId
// content.channelId;
... ... @@ -126,7 +128,7 @@ export class ProcessUtils {
params: {
contentID: content?.objectId,
pageID: 'IMAGE_TEXT_DETAIL',
extra:{
extra: {
relType: content?.relType,
relId: content?.relId,
channelId: content?.channelId,
... ... @@ -144,7 +146,7 @@ export class ProcessUtils {
params: {
detailPageType: 7,
contentID: content?.objectId,
extra:{
extra: {
relType: content?.relType,
relId: content?.relId,
} as ExtraDTO
... ... @@ -153,13 +155,23 @@ export class ProcessUtils {
WDRouterRule.jumpWithAction(taskAction)
Logger.debug(TAG, `gotoVod, ${content.objectId}`);
}
private static gotoLive(content: ContentDTO) {
private static async gotoLive(content: ContentDTO) {
const liveDetail = await LiveModel.getLiveDetails(content?.objectId || '', content?.relId || '', content?.relType || '')
const liveStyle = liveDetail[0].liveInfo.liveStyle
const liveState = liveDetail[0].liveInfo.liveState
console.error('liveDetail===', liveDetail)
let taskAction: Action = {
type: 'JUMP_DETAIL_PAGE',
params: {
detailPageType: 2,
contentID: content?.objectId,
extra:{
liveStyle: liveState === 'wait' ? 0 : liveStyle,
extra: {
relType: content?.relType,
relId: content?.relId,
} as ExtraDTO
... ... @@ -168,13 +180,14 @@ export class ProcessUtils {
WDRouterRule.jumpWithAction(taskAction)
Logger.debug(TAG, `gotoLive, ${content.objectId}`);
}
private static gotoAudio(content: ContentDTO) {
let taskAction: Action = {
type: 'JUMP_DETAIL_PAGE',
params: {
detailPageType: 13,
contentID: content?.objectId,
extra:{
extra: {
relType: content?.relType,
relId: content?.relId,
} as ExtraDTO
... ... @@ -183,5 +196,4 @@ export class ProcessUtils {
WDRouterRule.jumpWithAction(taskAction)
Logger.debug(TAG, `gotoAudio, ${content.objectId}`);
}
}
\ No newline at end of file
... ...
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 } from 'wdBean/Index';
const TAG = 'LiveModel'
export class LiveModel {
/**
* 直播内容详情
* @param contentId
* @param relId 关系id
* @param relType 关系类型;1.频道关系;2.专题关系;
* @returns
*/
static getLiveDetails(contentId: string, relId: string, relType: string) {
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return new Promise<Array<LiveDetailsBean>>((success, fail) => {
HttpRequest.get<ResponseDTO<Array<LiveDetailsBean>>>(
HttpUrlUtils.getLiveDetailsUrl() + `?relId=${relId}&relType=${relType}&contentId=${contentId}`,
headers).then((data: ResponseDTO<Array<LiveDetailsBean>>) => {
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())
})
})
}
}
... ...
import { BottomComponent } from '../widgets/details/BottomComponent';
import { TopPlayComponent } from '../widgets/details/video/TopPlayComponet';
import { TopPlayVComponent } from '../widgets/details/video/TopPlayVComponet';
import { Action, LiveDetailsBean, LiveRoomDataBean } from 'wdBean/Index';
import { LiveViewModel } from '../viewModel/LiveViewModel';
import router from '@ohos.router';
import { WindowModel } from 'wdKit/Index';
import { PlayerComponent } from '../widgets/vertical/PlayerComponent';
import { PlayerInfoComponent } from '../widgets/vertical/PlayerInfoComponent';
import { WDPlayerController } from 'wdPlayer/Index';
const storage = LocalStorage.getShared();
@Entry(storage)
@Component
export struct DetailPlayVLivePage {
TAG: string = 'DetailPlayLivePage';
private liveViewModel: LiveViewModel = new LiveViewModel()
private playerController: WDPlayerController = new WDPlayerController();
private swiperController: SwiperController = new SwiperController()
@Provide bottomSafeHeight: number = AppStorage.get<number>('bottomSafeHeight') || 0
@Provide topSafeHeight: number = AppStorage.get<number>('topSafeHeight') || 0
@Provide liveDetailsBean: LiveDetailsBean = {} as LiveDetailsBean
@Provide liveRoomDataBean: LiveRoomDataBean = {} as LiveRoomDataBean
@Provide isMenuVisible: boolean = false
@State relId: string = ''
@State contentId: string = ''
@State relType: string = ''
@State swiperIndex: number = 1
aboutToAppear(): void {
WindowModel.shared.setWindowLayoutFullScreen(true)
WindowModel.shared.setWindowSystemBarProperties({ statusBarContentColor: '#ffffff', })
//https://pdapis.pdnews.cn/api/rmrb-bff-display-zh/content/zh/c/content/detail?relId=500005302448&relType=1&contentId=20000016340
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()
}
aboutToDisappear(): void {
WindowModel.shared.setWindowLayoutFullScreen(false)
WindowModel.shared.setWindowSystemBarProperties({ statusBarContentColor: '#000000', })
}
build() {
Column() {
TopPlayVComponent()
// TabComponent()
BottomComponent()
Stack() {
PlayerComponent({
playerController: this.playerController
})
.onClick(() => {
this.isMenuVisible = !this.isMenuVisible
})
PlayerInfoComponent({
playerController: this.playerController,
swiperController: this.swiperController,
swiperIndex: $swiperIndex
})
Image($r('app.media.icon_live_more'))
.width(40)
.aspectRatio(1)// .visibility(this.swiperIndex === 0 ? Visibility.Visible : Visibility.Hidden)
.animation({ duration: 500 })
.position({ x: '95%', y: '95%' })
.onClick(() => {
this.swiperController.showNext()
})
}
.height('100%')
.width('100%')
}
.height('100%')
.width('100%')
... ... @@ -23,7 +82,29 @@ export struct DetailPlayVLivePage {
}
aboutToDisappear(): void {
getLiveDetails() {
this.liveViewModel.getLiveDetails(this.contentId, this.relId, this.relType)
.then(
(data) => {
if (data.length > 0) {
this.liveDetailsBean = data[0]
console.error('liveDetailsBean===', JSON.stringify((this.liveDetailsBean)))
}
},
() => {
})
}
getLiveRoomData() {
this.liveViewModel.getLiveRoomData(this.contentId)
.then(
(data) => {
this.liveRoomDataBean = data
},
() => {
})
}
}
... ...
import { window } from '@kit.ArkUI'
import { NumberFormatterUtils, WindowModel } from 'wdKit/Index'
import { devicePLSensorManager } from 'wdDetailPlayApi/Index'
import { DateFormatUtil, WDPlayerController } from 'wdPlayer/Index'
import { LiveDetailsBean, LiveRoomDataBean } from 'wdBean/Index'
@Entry
@Component
export struct PlayVUIComponent {
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 = DateFormatUtil.secondToTime(Math.floor(position / 1000));
this.totalTime = DateFormatUtil.secondToTime(Math.floor(duration / 1000));
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
})
if (this.liveDetailsBean.liveInfo?.liveState != 'wait') {
Text(this.liveDetailsBean.newsTitle)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontSize('16fp')
.fontWeight(500)
.fontColor(Color.White)
.textAlign(TextAlign.Start)
.layoutWeight(1)
} else {
Blank()
}
Image($r('app.media.icon_share'))
.width(24)
.aspectRatio(1)
.visibility(Visibility.None)
}
.width('100%')
.alignItems(VerticalAlign.Center)
.margin({
bottom: 10
})
this.getLiveStatusView()
}.width('100%')
.padding({
top: 20,
bottom: 6,
left: 10,
right: 10
})
.alignItems(HorizontalAlign.Start)
.visibility(this.isMenuVisible ? Visibility.Visible : Visibility.None)
}
@Builder
getLiveStatusView() {
// 直播新闻-直播状态 wait待开播running直播中end已结束cancel已取消paused暂停
// 预约
if (this.liveDetailsBean.liveInfo?.liveState == 'wait') {
Row() {
Image($r('app.media.icon_live_status_wait'))
.width(22)
.height(18)
Text('预约')
.fontSize('11fp')
.fontWeight(400)
.fontColor(Color.White)
}
.backgroundColor('#4D000000')
.padding({
top: 1,
right: 4,
bottom: 1
})
}
// 直播中
else if (this.liveDetailsBean.liveInfo?.liveState == 'running') {
Row() {
Image($r('app.media.icon_live_status_running'))
.width(22)
.height(18)
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({
top: 1,
right: 4,
bottom: 1
})
}
//回看
else if (this.liveDetailsBean.liveInfo?.liveState == 'end') {
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() {
if (this.liveDetailsBean?.liveInfo?.liveState == 'end') {
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
})
} else {
Blank()
}
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
})
.blockSize({
width: 18,
height: 12
})// .blockStyle({
// type: SliderBlockType.IMAGE,
// image: $r('app.media.ic_player_block')
// })
.blockColor(Color.White)
.trackColor('#4DFFFFFF')
.selectedColor('#FFED2800')
.height(14)
.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
... ...
@Component
export struct PlayerCommentComponent {
build() {
}
}
\ No newline at end of file
... ...
import { LiveDetailsBean } from 'wdBean/Index';
import { WDPlayerController, WDPlayerRenderVLiveView, WDPlayerRenderView } from 'wdPlayer/Index';
import componentUtils from '@ohos.arkui.componentUtils';
@Component
export struct PlayerComponent {
private playerController?: WDPlayerController;
// playerController: WDPlayerController = new WDPlayerController();
@Consume @Watch('updateData') liveDetailsBean: LiveDetailsBean
@State bottomSafeHeight: number = AppStorage.get<number>('bottomSafeHeight') || 0
@State topSafeHeight: number = AppStorage.get<number>('topSafeHeight') || 0
@State imgUrl: string = ''
@State isWait: boolean = false
@State liveStreamType: number | null = -1
aboutToAppear(): void {
if (this.playerController) {
this.playerController.onCanplay = () => {
console.log('可以播放了')
this.playerController?.play()
// this.playerController.selfSize
}
}
}
aboutToDisappear(): void {
this.playerController?.pause()
this.playerController?.stop()
this.playerController?.release()
}
updateData() {
console.error('updateData=============')
//直播新闻-直播状态 wait待开播running直播中end已结束cancel已取消paused暂停
if (this.liveDetailsBean.fullColumnImgUrls && this.liveDetailsBean.fullColumnImgUrls.length > 0) {
this.imgUrl = this.liveDetailsBean.fullColumnImgUrls[0].url
}
this.isWait = this.liveDetailsBean?.liveInfo?.liveState == 'wait'
if (this.liveDetailsBean.liveInfo && this.liveDetailsBean.liveInfo.vlive.length > 0) {
let playUrl = ''
let liveStreamType: number | null = null
if (this.liveDetailsBean.liveInfo.liveState == 'running') {
playUrl = this.liveDetailsBean.liveInfo.vlive[0].liveUrl
liveStreamType = this.liveDetailsBean.liveInfo.vlive[0].liveStreamType
} else if (this.liveDetailsBean.liveInfo.liveState == 'end') {
playUrl = this.liveDetailsBean.liveInfo.vlive[0].replayUri
liveStreamType = this.liveDetailsBean.liveInfo.vlive[0].liveStreamType
}
this.liveStreamType = liveStreamType
this.playerController?.firstPlay(playUrl);
}
}
build() {
Column() {
Stack() {
Image(this.imgUrl)
.height('100%')
.width('100%')
.blur(100)
// TODO:判断横竖屏,liveStreamType=1竖屏铺满屏幕,liveStreamType=0横屏正常展示
if (this.liveStreamType == null) {
WDPlayerRenderVLiveView({
playerController: this.playerController,
onLoad: () => {
}
}).height('100%')
.width('100%')
} else if (this.liveStreamType == 0) {
WDPlayerRenderView({
playerController: this.playerController,
onLoad: () => {
}
}).padding({ top: 195 })
}
}
.height('100%')
.width('100%')
.align(Alignment.Top)
.alignContent(Alignment.Top)
}
.height('100%')
.width('100%')
}
}
\ No newline at end of file
... ...
import { WDPlayerController } from 'wdPlayer/Index'
import { PlayerUIComponent } from './PlayerUIComponent'
@Component
export struct PlayerInfoComponent {
swiperController?: SwiperController
@Prop playerController: WDPlayerController
@Consume bottomSafeHeight: number
@Consume topSafeHeight: number
@Link swiperIndex: number
build() {
Column() {
Swiper(this.swiperController) {
Text('')
PlayerUIComponent({ playerController: this.playerController }).margin({
bottom: this.bottomSafeHeight + 'px',
top: this.topSafeHeight + 'px'
})
}
.cachedCount(2)
.indicator(false)
.loop(false)
.width('100%')
.height('100%')
.index(this.swiperIndex)
.onChange((index) => {
this.swiperIndex = index
})
}
.height('100%')
.width('100%')
}
}
\ No newline at end of file
... ...
import { LiveDetailsBean, LiveRoomDataBean } from 'wdBean/Index'
import { NumberFormatterUtils } from 'wdKit/Index'
@Component
export struct PlayerTitleComponent {
@Consume liveDetailsBean: LiveDetailsBean
@Consume liveRoomDataBean: LiveRoomDataBean
build() {
Column() {
Row() {
Image($r('app.media.icon_arrow_left_white'))
.width(24)
.aspectRatio(1)
.visibility(Visibility.None)
.margin({
right: 10
})
if (this.liveDetailsBean.liveInfo?.liveState != 'wait') {
Text(this.liveDetailsBean.newsTitle)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontSize('16fp')
.fontWeight(500)
.fontColor(Color.White)
.textAlign(TextAlign.Start)
.layoutWeight(1)
} else {
Blank()
}
Image($r('app.media.icon_share'))
.width(24)
.aspectRatio(1)
.visibility(Visibility.None)
}
.width('100%')
.alignItems(VerticalAlign.Center)
.margin({
bottom: 10
})
this.getLiveStatusView()
}.width('100%')
.padding({
top: 20,
bottom: 6,
left: 10,
right: 10
})
.alignItems(HorizontalAlign.Start)
.visibility(Visibility.Visible)
}
@Builder
getLiveStatusView() {
Row() {
Image(this.liveDetailsBean.rmhInfo.rmhHeadUrl)
.width(22)
.height(18)
Text(this.liveDetailsBean.rmhInfo.rmhName)
.fontSize('11fp')
.fontWeight(400)
.fontColor(Color.White)
}
.backgroundColor('#4D000000')
.padding({
top: 1,
right: 4,
bottom: 1
})
// 直播新闻-直播状态 wait待开播running直播中end已结束cancel已取消paused暂停
// 预约
if (this.liveDetailsBean.liveInfo?.liveState == 'wait') {
Row() {
Image($r('app.media.icon_live_status_wait'))
.width(22)
.height(18)
Text('预约')
.fontSize('11fp')
.fontWeight(400)
.fontColor(Color.White)
}
.backgroundColor('#4D000000')
.padding({
top: 1,
right: 4,
bottom: 1
})
}
// 直播中
else if (this.liveDetailsBean.liveInfo?.liveState == 'running') {
Row() {
Image($r('app.media.icon_live_status_running'))
.width(22)
.height(18)
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({
top: 1,
right: 4,
bottom: 1
})
}
//回看
else if (this.liveDetailsBean.liveInfo?.liveState == 'end') {
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
})
}
}
}
... ...
import { WDPlayerController } from 'wdPlayer/Index';
@Component
export struct PlayerUIComponent {
playerController: WDPlayerController = new WDPlayerController();
build() {
}
}
\ No newline at end of file
... ...
import { window } from '@kit.ArkUI'
import { NumberFormatterUtils, WindowModel } from 'wdKit/Index'
import { devicePLSensorManager } from 'wdDetailPlayApi/Index'
import { DateFormatUtil, WDPlayerController } from 'wdPlayer/Index'
import { LiveDetailsBean, LiveRoomDataBean } from 'wdBean/Index'
@Component
export struct PlayerVideoControlComponent {
playerController: WDPlayerController = new WDPlayerController();
@Consume liveDetailsBean: LiveDetailsBean
@Consume liveRoomDataBean: LiveRoomDataBean
//菜单键是否可见
@State isMenuVisible: boolean = true
@State isFullScreen: boolean = false
@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 = DateFormatUtil.secondToTime(Math.floor(position / 1000));
this.totalTime = DateFormatUtil.secondToTime(Math.floor(duration / 1000));
this.progressVal = Math.floor(position * 100 / duration);
}
}
build() {
Row() {
this.getBottomUIComponent()
}
}
@Builder
getBottomUIComponent() {
Row() {
if (this.liveDetailsBean?.liveInfo?.liveState == 'end') {
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
})
} else {
Blank()
}
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
})
.blockSize({
width: 18,
height: 12
})// .blockStyle({
// type: SliderBlockType.IMAGE,
// image: $r('app.media.ic_player_block')
// })
.blockColor(Color.White)
.trackColor('#4DFFFFFF')
.selectedColor('#FFED2800')
.height(14)
.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
... ...
{
"src": [
"pages/DetailPlayLivePage"
"pages/DetailPlayLivePage",
"pages/DetailPlayVLivePage"
]
}
\ No newline at end of file
... ...
... ... @@ -179,7 +179,6 @@ export struct DetailPlayShortVideoPage {
})
.height('100%')
.width('100%')
.margin({ top: this.contentDetailData?.videoInfo[0]?.videoLandScape === 1 ? 218 : 0 })
.onClick(() => {
console.error('WDPlayerRenderView=== onClick')
this.playerController?.switchPlayOrPause();
... ...
... ... @@ -166,8 +166,7 @@ export struct DetailVideoListPage {
})
}.width('100%')
.height('100%')
// 扩展至所有非安全区域
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
}, (item: ContentDetailDTO) => item.newsId + '')
}
.clip(false)
... ...
... ... @@ -61,6 +61,7 @@ export struct PlayerDetailContainer {
build() {
RelativeContainer() {
Row() {
Stack() {
Row() {
this.playerView()
... ... @@ -68,6 +69,7 @@ export struct PlayerDetailContainer {
.height('100%')
.width('100%')
.zIndex(0)
.margin({ top: this.videoLandScape === 1 ? 218 : 0 })
Row() {
this.playControlView()
... ... @@ -87,6 +89,7 @@ export struct PlayerDetailContainer {
// middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
.id('stk_player_container')
}.height('100%').layoutWeight(1)
if (this.isShowBottomView()) {
Row() {
... ...
export interface CheckVerifyBean{
temToken: string
tempToken: string
jwtToken: string
}
\ No newline at end of file
... ...
... ... @@ -200,36 +200,15 @@ export class LoginModel {
bean['tempToken'] = tempToken;
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
// let JwtToken = SPHelper.default.getSync(SpConstants.USER_JWT_TOKEN, '') as string;
// headers.set('JwtToken',(JwtToken));
// headers.set('rmrb-x-token',(JwtToken));
// headers.set('cookie', 'RMRB-X-TOKEN=' + JwtToken)
// let obj: Record<string, string> = {};
// headers.forEach((value, key) =>{
// if(key != undefined && key != null && value != undefined && value != null) {
// obj[key as string] = value;
// }
// })
// let headerString = JSON.stringify(obj);
// let beanString = JSON.stringify(bean);
// AlertDialog.show({
// message:headerString + beanString
// })
return new Promise<string>((success, fail) => {
HttpRequest.post<ResponseDTO<string>>(HttpUrlUtils.getForgetPasswordUrl(), bean, headers).then((data: ResponseDTO<string>) => {
return new Promise<object>((success, fail) => {
HttpRequest.post<ResponseDTO<object>>(HttpUrlUtils.getForgetPasswordUrl(), bean, headers).then((data: ResponseDTO<object>) => {
if (data.code != 0) {
fail(data.message)
return
}
if (!data || !data.data) {
fail("数据为空")
return
}
success(data.data)
success(data)
}, (error: Error) => {
fail(error.message)
Logger.debug("LoginViewModel:error ", error.toString())
... ...
... ... @@ -331,7 +331,7 @@ struct LoginPage {
router.back({
params: { userName: data.userName,
userId:data.id},
url: 'pages/MainPage'
url: `${WDRouterPage.getBundleInfo()}`
})
}).catch((value: string) => {
promptAction.showToast({ message: value })
... ...
... ... @@ -95,7 +95,7 @@ export class LoginViewModel {
return new Promise<CheckVerifyBean>((success, reject) => {
this.loginModel.checkVerifyCode(phone, verifyCode).then((data: CheckVerifyBean) => {
//todo 保存数据
SPHelper.default.save(SpConstants.USER_TEMP_TOKEN, data.temToken)
SPHelper.default.save(SpConstants.USER_TEMP_TOKEN, data.tempToken)
SPHelper.default.save(SpConstants.USER_JWT_TOKEN, data.jwtToken)
success(data)
... ... @@ -108,7 +108,7 @@ export class LoginViewModel {
return new Promise<CheckVerifyBean>((success, reject) => {
this.loginModel.checkVerifyCodeByToken(verifyCode).then((data: CheckVerifyBean) => {
//todo 保存数据
SPHelper.default.save(SpConstants.USER_TEMP_TOKEN, data.temToken)
SPHelper.default.save(SpConstants.USER_TEMP_TOKEN, data.tempToken)
SPHelper.default.save(SpConstants.USER_JWT_TOKEN, data.jwtToken)
success(data)
... ... @@ -134,7 +134,7 @@ export class LoginViewModel {
//忘记密码
forgotPassword(password: string, tempToken: string) {
return new Promise<string>(async (success, fail) => {
return new Promise<object>(async (success, fail) => {
let passwordNew = await encryptMessage(password)
this.loginModel.forgotPassword(passwordNew, tempToken).then((data) => {
success(data)
... ...
... ... @@ -3,7 +3,7 @@ import promptAction from '@ohos.promptAction';
import { Params } from '../../../../../../../commons/wdRouter/oh_modules/wdBean/Index';
import router from '@ohos.router';
import { LoginViewModel } from './LoginViewModel';
import { Logger, SPHelper } from 'wdKit';
import { Logger, SPHelper, ToastUtils } from 'wdKit';
import {
SpConstants
} from '../../../../../../../commons/wdNetwork/oh_modules/wdConstant/src/main/ets/constants/SpConstants'
... ... @@ -303,7 +303,7 @@ export struct SettingPasswordLayout {
/***************************** 事件处理 ******************************************/
// 提交按钮点击事件
buttonClick() {
async buttonClick() {
if (this.btnStatus) {
// 需要+手机号校验
if (this.password01.length < 6 || this.password01.length > 20) {
... ... @@ -315,18 +315,27 @@ export struct SettingPasswordLayout {
return
}
if(this.pageId == 1){ //设置密码
SPHelper.default.get(SpConstants.USER_JWT_TOKEN, '').then((str) => {
SPHelper.default.get(SpConstants.USER_TEMP_TOKEN, '').then((str) => {
this.loginViewModel.forgotPassword(this.password01, str.toString()).then((data =>{
if (this.pageType == 0) {//登录页
WDRouterRule.jumpWithPage(WDRouterPage.loginPage);
ToastUtils.shortToast("修改成功")
router.back({
url: `${WDRouterPage.getLoginBundleInfo()}`
})
}else if(this.pageType == 1){//设置
let params: Params = {
pageID: 'AccountAndSecurityLayout'
}
WDRouterRule.jumpWithPage(WDRouterPage.settingPage, params)
ToastUtils.shortToast("修改成功")
router.back({
params:params,
url: `${WDRouterPage.getSettingBundleInfo()}`
})
// WDRouterRule.jumpWithPage(WDRouterPage.settingPage, params)
}
}))
}).catch((err: Error) => {
}).catch((err: string) => {
ToastUtils.shortToast(err)
Logger.error(TAG, 'catch err:' + JSON.stringify(err));
});
}
... ...
... ... @@ -4,6 +4,8 @@ export { WDPlayerRenderView } from "./src/main/ets/pages/WDPlayerRenderView"
export { WDPlayerRenderLiveView } from "./src/main/ets/pages/WDPlayerRenderLiveView"
export { WDPlayerRenderVLiveView } from "./src/main/ets/pages/WDPlayerRenderVLiveView"
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 = 'WDPlayerRenderView'
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 WDPlayerRenderVLiveView {
private playerController?: WDPlayerController;
private xComponentController: XComponentController = new XComponentController();
private insId: string = "WDPlayRenderView" + insIndex;
onLoad?: ((event?: object) => void);
@State videoWidth: number = 0
@State videoHeight: number = 0
@State selfSize: Size = new Size('100%', '100%');
aboutToAppear() {
MGPlayRenderViewIns.add();
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')
// const surfaceId = this.xComponentController.getXComponentSurfaceId()
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)
.height('100%')
.width('100%')
}
.id(this.insId)
.onAreaChange(() => {
// this.updateLayout()
})
.backgroundColor("#000000")
.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
... ...
... ... @@ -97,6 +97,9 @@ export struct WDPlayerRenderView {
// this.updateLayout()
})
.backgroundColor("#000000")
// .height('100%')
// .width('100%')
}
updateLayout() {
... ...