Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
galaxy-iOS
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
mobile-group
galaxy-iOS
Commits
1b6dc0bc
Commit
1b6dc0bc
authored
Dec 05, 2024
by
Alex朱枝文
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
录播以及bug修复
parent
415fa600
Changes
32
Hide whitespace changes
Inline
Side-by-side
Showing
32 changed files
with
924 additions
and
392 deletions
+924
-392
project.pbxproj
galaxy/galaxy.xcodeproj/project.pbxproj
+8
-0
YHBasePlayerViewController.swift
.../LivestreamSales(直播销售)/C/YHBasePlayerViewController.swift
+3
-55
YHLivePlayerViewController.swift
.../LivestreamSales(直播销售)/C/YHLivePlayerViewController.swift
+135
-75
YHPlayer.swift
...xy/Classes/Modules/LivestreamSales(直播销售)/C/YHPlayer.swift
+7
-116
YHPlayerManager.swift
...ses/Modules/LivestreamSales(直播销售)/C/YHPlayerManager.swift
+28
-24
YHVODPlayerViewController.swift
...s/LivestreamSales(直播销售)/C/YHVODPlayerViewController.swift
+239
-70
YHIMHelper.swift
...ses/Modules/LivestreamSales(直播销售)/IM(环信)/YHIMHelper.swift
+5
-0
YHLiveCreateOrderModel.swift
...ules/LivestreamSales(直播销售)/M/YHLiveCreateOrderModel.swift
+17
-0
YHLiveDetailModel.swift
...s/Modules/LivestreamSales(直播销售)/M/YHLiveDetailModel.swift
+1
-0
YHRecordedDetailModel.swift
...dules/LivestreamSales(直播销售)/M/YHRecordedDetailModel.swift
+6
-4
YHLiveMessageCell.swift
...s/Modules/LivestreamSales(直播销售)/V/YHLiveMessageCell.swift
+6
-0
YHLiveMessageListView.swift
...dules/LivestreamSales(直播销售)/V/YHLiveMessageListView.swift
+4
-1
YHLiveShopView.swift
...sses/Modules/LivestreamSales(直播销售)/V/YHLiveShopView.swift
+30
-25
YHVideoProgressControl.swift
...ules/LivestreamSales(直播销售)/V/YHVideoProgressControl.swift
+295
-0
YHLiveSalesViewModel.swift
...dules/LivestreamSales(直播销售)/VM/YHLiveSalesViewModel.swift
+28
-21
YhConstant.swift
galaxy/galaxy/Classes/Tools/Helper/YhConstant.swift
+0
-1
YHAllApiName.swift
galaxy/galaxy/Classes/Tools/NetWork/YHAllApiName.swift
+2
-0
Contents.json
...xcassets/YinHeLive/live_icon_pause.imageset/Contents.json
+22
-0
live_icon_pause@2x.png
...YinHeLive/live_icon_pause.imageset/live_icon_pause@2x.png
+0
-0
live_icon_pause@3x.png
...YinHeLive/live_icon_pause.imageset/live_icon_pause@3x.png
+0
-0
Contents.json
....xcassets/YinHeLive/live_icon_play.imageset/Contents.json
+22
-0
live_icon_play@2x.png
...s/YinHeLive/live_icon_play.imageset/live_icon_play@2x.png
+0
-0
live_icon_play@3x.png
...s/YinHeLive/live_icon_play.imageset/live_icon_play@3x.png
+0
-0
Contents.json
...ssets/YinHeLive/live_msg_tips_icon.imageset/Contents.json
+22
-0
live_msg_tips_icon@2x.png
...ive/live_msg_tips_icon.imageset/live_msg_tips_icon@2x.png
+0
-0
live_msg_tips_icon@3x.png
...ive/live_msg_tips_icon.imageset/live_msg_tips_icon@3x.png
+0
-0
Contents.json
...assets/YinHeLive/live_slider_thumb.imageset/Contents.json
+22
-0
live_slider_thumb@2x.png
...eLive/live_slider_thumb.imageset/live_slider_thumb@2x.png
+0
-0
live_slider_thumb@3x.png
...eLive/live_slider_thumb.imageset/live_slider_thumb@3x.png
+0
-0
Contents.json
...sets/YinHeLive/live_time_separator.imageset/Contents.json
+22
-0
live_time_separator@2x.png
...e/live_time_separator.imageset/live_time_separator@2x.png
+0
-0
live_time_separator@3x.png
...e/live_time_separator.imageset/live_time_separator@3x.png
+0
-0
No files found.
galaxy/galaxy.xcodeproj/project.pbxproj
View file @
1b6dc0bc
...
...
@@ -858,6 +858,8 @@
04F957452C1FEC4A003C631C
/* YHMessageBellView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04F957442C1FEC4A003C631C
/* YHMessageBellView.swift */
;
};
04F957472C203033003C631C
/* YHMyGoodFriendsVC.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04F957462C203033003C631C
/* YHMyGoodFriendsVC.swift */
;
};
04F9574B2C2032D8003C631C
/* YHMyFriendsCell.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04F9574A2C2032D8003C631C
/* YHMyFriendsCell.swift */
;
};
04F98A2F2D00543500B1CC0A
/* YHLiveCreateOrderModel.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04F98A2E2D00543500B1CC0A
/* YHLiveCreateOrderModel.swift */
;
};
04F98A312D00889C00B1CC0A
/* YHVideoProgressControl.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04F98A302D00889C00B1CC0A
/* YHVideoProgressControl.swift */
;
};
04FA8B2B2C06F59D00ABE43F
/* YHAppleLoginManager.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04FA8B2A2C06F59D00ABE43F
/* YHAppleLoginManager.swift */
;
};
04FA8B2E2C084C7E00ABE43F
/* ATAuthSDK.bundle in Resources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04FA8B2D2C084C7E00ABE43F
/* ATAuthSDK.bundle */
;
};
04FA8B302C0874CA00ABE43F
/* YHOneKeyLoginViewModel.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04FA8B2F2C0874CA00ABE43F
/* YHOneKeyLoginViewModel.swift */
;
};
...
...
@@ -1969,6 +1971,8 @@
04F957442C1FEC4A003C631C
/* YHMessageBellView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHMessageBellView.swift
;
sourceTree
=
"<group>"
;
};
04F957462C203033003C631C
/* YHMyGoodFriendsVC.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHMyGoodFriendsVC.swift
;
sourceTree
=
"<group>"
;
};
04F9574A2C2032D8003C631C
/* YHMyFriendsCell.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHMyFriendsCell.swift
;
sourceTree
=
"<group>"
;
};
04F98A2E2D00543500B1CC0A
/* YHLiveCreateOrderModel.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHLiveCreateOrderModel.swift
;
sourceTree
=
"<group>"
;
};
04F98A302D00889C00B1CC0A
/* YHVideoProgressControl.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHVideoProgressControl.swift
;
sourceTree
=
"<group>"
;
};
04FA8B2A2C06F59D00ABE43F
/* YHAppleLoginManager.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHAppleLoginManager.swift
;
sourceTree
=
"<group>"
;
};
04FA8B2D2C084C7E00ABE43F
/* ATAuthSDK.bundle */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
"wrapper.plug-in"
;
name
=
ATAuthSDK.bundle
;
path
=
"galaxy/Classes/Modules/AutoLogin(一键登录)/framework/ATAuthSDK_D.framework/ATAuthSDK.bundle"
;
sourceTree
=
"<group>"
;
};
04FA8B2F2C0874CA00ABE43F
/* YHOneKeyLoginViewModel.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHOneKeyLoginViewModel.swift
;
sourceTree
=
"<group>"
;
};
...
...
@@ -3077,6 +3081,7 @@
04013E412CFADF6B001A8E40
/* YHShareAlertView.swift */
,
04013E452CFDA9AD001A8E40
/* YHLiveShopView.swift */
,
0413A9B02CFFDB9A00304BC6
/* YHCategoryDropdownView.swift */
,
04F98A302D00889C00B1CC0A
/* YHVideoProgressControl.swift */
,
);
path
=
V
;
sourceTree
=
"<group>"
;
...
...
@@ -3088,6 +3093,7 @@
04564D692CF6C0FC004456E4
/* YHLiveDetailModel.swift */
,
04564D6D2CF6EB3D004456E4
/* YHHuanXinUserModel.swift */
,
04564D6F2CF6EC8A004456E4
/* YHRecordedDetailModel.swift */
,
04F98A2E2D00543500B1CC0A
/* YHLiveCreateOrderModel.swift */
,
);
path
=
M
;
sourceTree
=
"<group>"
;
...
...
@@ -6385,6 +6391,7 @@
045EEEDF2B9F171A0022A143
/* YHCollegeSearchBar.swift in Sources */
,
0471BF622CBA9046003B7942
/* YHHKVisaRenewalPersonType.swift in Sources */
,
044D0BEE2C2019C100C5CF5E
/* YHCommunityViewController.swift in Sources */
,
04F98A312D00889C00B1CC0A
/* YHVideoProgressControl.swift in Sources */
,
A567E5B52BD7643D00D5D5A0
/* YHSearchInfoBar.swift in Sources */
,
044EE2462C93E22E00A2FE3A
/* YHResignCertificateDetailHkViewController.swift in Sources */
,
A5ACE94B2B4564F7002C94D2
/* YHHUDRotatingImageView.swift in Sources */
,
...
...
@@ -6963,6 +6970,7 @@
045EEE872B9F171A0022A143
/* YHPreviewControllerHoldViewController.swift in Sources */
,
0419A0A22C49099A00A5FCFA
/* YHInvitationWithGiftsShareBottomView.swift in Sources */
,
04AAA8DC2BF5E5A200FE9FD5
/* YHEmptyDataView.swift in Sources */
,
04F98A2F2D00543500B1CC0A
/* YHLiveCreateOrderModel.swift in Sources */
,
044F39502CB80706007CA277
/* YHVisaRenewalPayStatusCell.swift in Sources */
,
A5A89FD72C256B94005A71DD
/* YHHomeLastMessageModel.swift in Sources */
,
045EEF172B9F171A0022A143
/* YHSelectCountryViewController.swift in Sources */
,
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/C/YHBasePlayerViewController.swift
View file @
1b6dc0bc
...
...
@@ -32,12 +32,6 @@ class YHBasePlayerViewController: YHBaseViewController {
return
view
}()
private(set)
lazy
var
controlView
:
YHPlayerControlView
=
{
let
view
=
YHPlayerControlView
()
view
.
delegate
=
self
return
view
}()
lazy
var
topBarView
:
YHPlayerTopBarView
=
{
let
view
=
YHPlayerTopBarView
(
frame
:
CGRect
(
x
:
0
,
y
:
0
,
width
:
KScreenWidth
,
height
:
k_Height_NavigationtBarAndStatuBar
))
return
view
...
...
@@ -51,13 +45,12 @@ class YHBasePlayerViewController: YHBaseViewController {
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
setupUI
()
setupGestures
()
//
setupGestures()
setupNotifications
()
}
override
func
viewWillAppear
(
_
animated
:
Bool
)
{
super
.
viewWillAppear
(
animated
)
// navigationController?.setNavigationBarHidden(true, animated: animated)
gk_navBarAlpha
=
0
gk_navigationBar
.
isHidden
=
true
view
.
backgroundColor
=
.
black
...
...
@@ -65,7 +58,6 @@ class YHBasePlayerViewController: YHBaseViewController {
override
func
viewWillDisappear
(
_
animated
:
Bool
)
{
super
.
viewWillDisappear
(
animated
)
// navigationController?.setNavigationBarHidden(false, animated: animated)
gk_navBarAlpha
=
1
gk_navigationBar
.
isHidden
=
false
view
.
backgroundColor
=
.
black
...
...
@@ -84,7 +76,6 @@ class YHBasePlayerViewController: YHBaseViewController {
view
.
backgroundColor
=
.
black
view
.
addSubview
(
containerView
)
containerView
.
addSubview
(
playerView
)
containerView
.
addSubview
(
controlView
)
containerView
.
addSubview
(
topBarView
)
setupConstraints
()
}
...
...
@@ -98,10 +89,6 @@ class YHBasePlayerViewController: YHBaseViewController {
make
.
edges
.
equalToSuperview
()
}
controlView
.
snp
.
makeConstraints
{
make
in
make
.
edges
.
equalToSuperview
()
}
topBarView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
left
.
right
.
equalToSuperview
()
make
.
height
.
equalTo
(
k_Height_NavigationtBarAndStatuBar
)
...
...
@@ -120,7 +107,7 @@ class YHBasePlayerViewController: YHBaseViewController {
private
func
toggleControls
()
{
isControlsVisible
.
toggle
()
controlView
.
showControls
(
isControlsVisible
)
//
controlView.showControls(isControlsVisible)
resetControlsAutoHideTimer
()
}
...
...
@@ -135,49 +122,10 @@ class YHBasePlayerViewController: YHBaseViewController {
private
func
hideControls
()
{
isControlsVisible
=
false
controlView
.
showControls
(
false
)
//
controlView.showControls(false)
}
}
// MARK: - YHPlayerControlViewDelegate
extension
YHBasePlayerViewController
:
YHPlayerControlViewDelegate
{
func
playerControlView
(
_
view
:
YHPlayerControlView
,
didTapBack
button
:
UIButton
)
{
if
let
navigationController
=
navigationController
{
navigationController
.
popViewController
(
animated
:
true
)
}
else
{
dismiss
(
animated
:
true
)
}
}
func
playerControlView
(
_
view
:
YHPlayerControlView
,
didTapPlay
button
:
UIButton
)
{
if
player
?
.
getPlayState
()
==
.
playing
{
YHPlayerManager
.
shared
.
pause
()
}
else
{
YHPlayerManager
.
shared
.
resume
()
}
}
func
playerControlView
(
_
view
:
YHPlayerControlView
,
didSeekTo
position
:
Float
)
{
guard
let
player
=
player
else
{
return
}
let
duration
=
player
.
getDuration
()
let
targetPosition
=
Int
(
Float
(
duration
)
*
position
)
player
.
playerKit
?
.
seek
(
toPosition
:
targetPosition
)
}
func
playerControlView
(
_
view
:
YHPlayerControlView
,
didChangeQuality
quality
:
YHVideoQuality
)
{
// 由子类实现
}
func
playerControlView
(
_
view
:
YHPlayerControlView
,
didTapFullscreen
button
:
UIButton
)
{
if
UIDevice
.
current
.
orientation
.
isPortrait
{
let
value
=
UIInterfaceOrientation
.
landscapeRight
.
rawValue
UIDevice
.
current
.
setValue
(
value
,
forKey
:
"orientation"
)
}
else
{
let
value
=
UIInterfaceOrientation
.
portrait
.
rawValue
UIDevice
.
current
.
setValue
(
value
,
forKey
:
"orientation"
)
}
}
}
// MARK: - Notifications
extension
YHBasePlayerViewController
{
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/C/YHLivePlayerViewController.swift
View file @
1b6dc0bc
...
...
@@ -6,12 +6,13 @@
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import
HyphenateChat
import
AgoraRtcKit
import
HyphenateChat
import
UIKit
class
YHLivePlayerViewController
:
YHBasePlayerViewController
{
// MARK: - Properties
private
let
liveId
:
Int
private
var
roomId
:
String
?
private
let
messageQueue
=
DispatchQueue
(
label
:
"com.livePlayerRoom.messageQueue"
)
...
...
@@ -22,8 +23,9 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
private
var
listMaxWidth
:
CGFloat
{
return
KScreenWidth
*
248.0
/
375.0
}
// MARK: - UI Components
private
lazy
var
bottomInputBar
:
YHInputBottomBar
=
{
let
view
=
YHInputBottomBar
()
view
.
textViewTappedEvent
=
{
[
weak
self
]
in
...
...
@@ -31,7 +33,7 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
return
view
}()
private
lazy
var
inputVC
:
YHMessageInputViewController
=
{
let
ctl
=
YHMessageInputViewController
()
ctl
.
inputCallback
=
{
[
weak
self
]
controller
,
text
in
...
...
@@ -39,22 +41,22 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
return
ctl
}()
private
lazy
var
messageListView
:
YHLiveMessageListView
=
{
let
view
=
YHLiveMessageListView
(
frame
:
CGRect
(
x
:
0
,
y
:
0
,
width
:
listMaxWidth
,
height
:
listMaxWidth
))
return
view
}()
private
lazy
var
liveStateVC
:
YHLiveStateViewController
=
{
let
vc
=
YHLiveStateViewController
()
vc
.
shareEvent
=
{
[
weak
self
]
in
self
?
.
shareLive
()
}
vc
.
closeEvent
=
{
[
weak
self
]
in
self
?
.
closeLive
()
}
vc
.
backHomeEvent
=
{
[
weak
self
]
in
self
?
.
closeLive
()
UIViewController
.
current
?
.
navigationController
?
.
popToRootViewController
(
animated
:
false
)
...
...
@@ -62,25 +64,27 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
return
vc
}()
// MARK: - Initialization
init
(
id
:
Int
,
url
:
String
?
=
nil
,
title
:
String
?
=
nil
,
roomId
:
String
?
=
nil
)
{
self
.
liveId
=
id
liveId
=
id
self
.
roomId
=
roomId
super
.
init
(
nibName
:
nil
,
bundle
:
nil
)
// 隐藏播控UI
controlView
.
isHidden
=
true
player
?
.
delegate
=
self
// 设置播放器代理
//
controlView.isHidden = true
player
?
.
delegate
=
self
// 设置播放器代理
if
let
roomId
=
roomId
{
setupChatRoom
(
roomId
:
roomId
)
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
// MARK: - Lifecycle
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
modalPresentationStyle
=
.
fullScreen
...
...
@@ -91,53 +95,53 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
joinLiveRoom
(
id
:
liveId
,
callback
:
{
_
,
_
in
})
}
}
deinit
{
NotificationCenter
.
default
.
removeObserver
(
self
)
quitChatRoom
()
}
// MARK: - Setup
private
func
setupLiveUI
()
{
containerView
.
addSubview
(
bottomInputBar
)
containerView
.
addSubview
(
messageListView
)
bottomInputBar
.
snp
.
makeConstraints
{
make
in
make
.
left
.
right
.
bottom
.
equalToSuperview
()
make
.
top
.
equalTo
(
view
.
safeAreaLayoutGuide
.
snp
.
bottom
)
.
offset
(
-
YHInputBottomBar
.
inputActionHeight
)
}
messageListView
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
16
)
make
.
bottom
.
equalTo
(
bottomInputBar
.
snp
.
top
)
.
offset
(
-
14
)
make
.
height
.
width
.
equalTo
(
listMaxWidth
)
}
topBarView
.
closeButtonClickEvent
=
{
[
weak
self
]
in
self
?
.
closeLive
()
}
topBarView
.
zoomButtonClickEvent
=
{
[
weak
self
]
in
self
?
.
enterFloating
()
}
topBarView
.
shareButtonClickEvent
=
{
[
weak
self
]
in
self
?
.
shareLive
()
}
bottomInputBar
.
giftButtonClickEvent
=
{
[
weak
self
]
in
self
?
.
showGoods
()
}
}
private
func
setupStateViewController
()
{
isLiveStateOn
=
true
// 1. 添加子控制器
// addChild(liveStateVC)
view
.
addSubview
(
liveStateVC
.
view
)
view
.
bringSubviewToFront
(
liveStateVC
.
view
)
liveStateVC
.
view
.
isUserInteractionEnabled
=
true
// 2. 使用SnapKit设置约束
liveStateVC
.
view
.
snp
.
makeConstraints
{
make
in
make
.
edges
.
equalToSuperview
()
...
...
@@ -153,11 +157,11 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
liveStateVC
.
view
.
removeFromSuperview
()
// liveStateVC.removeFromParent()
}
private
func
setupData
()
{
viewModel
.
getLiveDetail
(
id
:
liveId
)
{
[
weak
self
]
liveDetail
,
error
in
guard
let
self
=
self
else
{
return
}
if
let
liveDetail
=
liveDetail
{
self
.
handleLiveDetailSuccess
(
liveDetail
)
}
else
{
...
...
@@ -169,7 +173,7 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
}
}
private
func
handleLiveDetailSuccess
(
_
liveDetail
:
YHLiveDetailModel
,
needJoinIMRoom
:
Bool
=
true
,
needJoinLiveChannel
:
Bool
=
true
)
{
// 更新顶部栏信息
topBarView
.
setupTopBarView
(
...
...
@@ -179,6 +183,7 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
)
playbackInfo
?
.
channelId
=
liveDetail
.
rtmp_channel
playbackInfo
?
.
token
=
liveDetail
.
token
playbackInfo
?
.
title
=
liveDetail
.
live_title
if
needJoinLiveChannel
{
if
!
liveDetail
.
rtmp_channel
.
isEmpty
,
!
liveDetail
.
token
.
isEmpty
,
let
uid
=
playbackInfo
?
.
uid
,
let
player
=
player
{
player
.
setPlayView
(
playerView
)
...
...
@@ -202,12 +207,12 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
removeStateViewController
()
}
}
private
func
setupChatRoom
(
roomId
:
String
)
{
// 初始化聊天室
joinChatRoom
(
roomId
:
roomId
)
}
private
func
setupLiveNotifications
()
{
NotificationCenter
.
default
.
addObserver
(
self
,
...
...
@@ -215,47 +220,48 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
name
:
YHIMHelper
.
didChatManagerReceiveMessages
,
object
:
nil
)
NotificationCenter
.
default
.
addObserver
(
self
,
selector
:
#selector(
didLoginEaseIMSuccess
)
,
name
:
YHIMHelper
.
didLoginEaseIMSuccess
,
object
:
nil
)
NotificationCenter
.
default
.
addObserver
(
self
,
selector
:
#selector(
didLogOutEaseIM
)
,
name
:
YHIMHelper
.
didLogOutEaseIM
,
object
:
nil
)
NotificationCenter
.
default
.
addObserver
(
self
,
selector
:
#selector(
didLoginYH
)
,
name
:
YhConstant
.
YhNotification
.
didLoginSuccessNotifiction
,
object
:
nil
)
NotificationCenter
.
default
.
addObserver
(
self
,
selector
:
#selector(
didLogOutYH
)
,
name
:
YhConstant
.
YhNotification
.
didLogoutSuccessNotifiction
,
object
:
nil
)
NotificationCenter
.
default
.
addObserver
(
self
,
selector
:
#selector(
didJoinedOfUid
)
,
name
:
Notification
.
Name
(
"com.YHPlayerManager.didJoinedOfUid"
),
object
:
nil
)
}
// MARK: - Public Methods
func
play
(
url
:
String
,
title
:
String
?
=
nil
)
{
currentPlayingURL
=
url
currentVideoTitle
=
title
controlView
.
setTitle
(
title
??
""
)
//
controlView.setTitle(title ?? "")
YHPlayerManager
.
shared
.
play
(
url
:
url
,
inView
:
playerView
,
title
:
title
)
}
func
enterFloating
()
{
guard
let
playbackInfo
=
playbackInfo
else
{
return
}
//player?.setPlayViewNull()
YHPlayerManager
.
shared
.
enterFloating
(
from
:
self
,
playbackInfo
:
playbackInfo
)
}
// MARK: - Chat Room Methods
private
func
joinChatRoom
(
roomId
:
String
)
{
YHIMHelper
.
shared
.
joinChatRoom
(
roomID
:
roomId
,
leaveOtherRooms
:
true
)
{
[
weak
self
]
error
in
guard
let
self
=
self
else
{
return
}
if
let
error
=
error
{
printLog
(
"joinChatRoom:
\(
error
)
"
)
}
else
{
...
...
@@ -263,15 +269,18 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
}
}
private
func
loadHistoryMessages
(
roomId
:
String
)
{
YHIMHelper
.
shared
.
fetchHistoryMessage
(
roomID
:
roomId
)
{
[
weak
self
]
list
,
error
in
YHIMHelper
.
shared
.
fetchHistoryMessage
(
roomID
:
roomId
)
{
[
weak
self
]
list
,
_
in
guard
let
self
=
self
,
let
messages
=
list
else
{
return
}
self
.
messageListView
.
clearMessages
()
if
let
tips
=
self
.
viewModel
.
liveDetailModel
?
.
tips
,
tips
.
count
>
0
{
self
.
appendTipsMessage
(
tips
)
}
self
.
appendHistoryMessages
(
messages
)
}
}
private
func
leaveLiveRoom
()
{
guard
YHLoginManager
.
shared
.
isLogin
()
else
{
return
...
...
@@ -284,10 +293,10 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
}
}
private
func
quitChatRoom
()
{
guard
let
roomId
=
roomId
else
{
return
}
YHIMHelper
.
shared
.
quitChatRoom
(
roomID
:
roomId
)
{
error
in
if
let
error
=
error
{
printLog
(
"quitChatRoom:
\(
error
)
"
)
...
...
@@ -296,24 +305,24 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
}
}
private
func
closeLive
()
{
quitChatRoom
()
leaveLiveRoom
()
//YHPlayerManager.shared.stop(type: .main)
//
YHPlayerManager.shared.stop(type: .main)
if
let
player
=
player
{
YHPlayerManager
.
shared
.
leaveChannel
(
for
:
player
)
}
dismiss
(
animated
:
true
)
}
private
func
shareLive
()
{
guard
let
liveModel
=
viewModel
.
liveDetailModel
else
{
return
}
YHShareAlertView
.
show
(
image
:
liveModel
.
live_image
,
title
:
"@"
+
liveModel
.
account
,
subMessage
:
liveModel
.
live_title
,
linkUrl
:
liveModel
.
live_h5_url
,
isLive
:
true
)
}
private
func
showGoods
()
{
let
list
=
viewModel
.
liveDetailModel
?
.
goods
??
[]
let
view
=
YHLiveShopView
.
show
{
[
weak
self
]
index
in
...
...
@@ -327,9 +336,54 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
view
.
closeEvent
=
{
[
weak
self
]
in
self
?
.
goodsListView
=
nil
}
view
.
buyData
=
{
[
weak
self
]
index
in
guard
list
.
count
>
index
else
{
return
}
let
model
=
list
[
index
]
self
?
.
createOrder
(
id
:
model
.
id
)
}
goodsListView
=
view
}
private
func
createOrder
(
id
:
Int
)
{
YHHUD
.
show
(
.
progress
(
message
:
"加载中..."
))
viewModel
.
createOrder
(
source
:
1
,
sourceId
:
liveId
,
productId
:
id
)
{
[
weak
self
]
orderModel
,
error
in
YHHUD
.
hide
()
guard
let
self
=
self
else
{
return
}
guard
let
orderModel
=
orderModel
else
{
if
let
errorMsg
=
error
?
.
errorMsg
,
errorMsg
.
count
>
0
{
YHHUD
.
flash
(
message
:
errorMsg
)
}
return
}
var
url
=
YHBaseUrlManager
.
shared
.
curH5URL
()
+
"superAppBridge.html#/order/order-confirm"
+
"?id=
\(
orderModel
.
id
)
"
if
YHLoginManager
.
shared
.
isLogin
()
{
let
token
=
YHLoginManager
.
shared
.
h5Token
let
urlHasParam
=
String
.
hasQueryParameters
(
urlString
:
url
)
if
urlHasParam
{
url
=
url
+
"¶m="
+
token
}
else
{
url
=
url
+
"?param="
+
token
}
}
var
tUrl
=
url
if
!
url
.
contains
(
"navigationH="
)
{
tUrl
=
url
+
"?navigationH=
\(
k_Height_NavigationtBarAndStatuBar
)
"
if
url
.
contains
(
"?"
)
{
tUrl
=
url
+
"&navigationH=
\(
k_Height_NavigationtBarAndStatuBar
)
"
}
}
let
vc
=
YHH5WebViewVC
()
vc
.
url
=
tUrl
vc
.
isHideNavigationBar
=
false
goodsListView
?
.
dismiss
()
navigationController
?
.
pushViewController
(
vc
)
}
}
private
func
gotoH5GoodsDetail
(
id
:
Int
)
{
var
url
=
YHBaseUrlManager
.
shared
.
curH5URL
()
+
"superAppBridge.html#/goods/sales-detail"
+
"?id=
\(
id
)
"
if
YHLoginManager
.
shared
.
isLogin
()
{
...
...
@@ -354,15 +408,16 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
goodsListView
?
.
dismiss
()
navigationController
?
.
pushViewController
(
vc
)
}
// MARK: - Message Handling
private
func
handleMessageInput
(
text
:
String
,
controller
:
YHMessageInputViewController
)
{
guard
checkLogin
(),
let
roomId
=
roomId
else
{
return
}
YHIMHelper
.
shared
.
sendMessage
(
roomID
:
roomId
,
sendText
:
text
)
{
[
weak
self
]
message
,
error
in
guard
let
self
=
self
else
{
return
}
if
let
message
=
message
{
controller
.
updateText
(
""
)
controller
.
closeKeyboard
(
nil
)
...
...
@@ -393,7 +448,18 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
}
}
private
func
appendTipsMessage
(
_
tips
:
String
)
{
messageQueue
.
async
{
let
body
=
EMCustomMessageBody
(
event
:
YHChatRoomCustomLocal
.
tipsEvent
,
customExt
:
[
YHChatRoomCustomLocal
.
tipsKey
:
tips
])
let
message
=
EMChatMessage
(
conversationID
:
self
.
roomId
??
""
,
body
:
body
,
ext
:
nil
)
message
.
chatType
=
.
chatRoom
DispatchQueue
.
main
.
async
{
self
.
messageListView
.
addMessages
([
message
])
}
}
}
private
func
checkLogin
()
->
Bool
{
if
!
YHLoginManager
.
shared
.
isLogin
()
{
YHOneKeyLoginManager
.
shared
.
oneKeyLogin
()
...
...
@@ -401,9 +467,9 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
return
true
}
// MARK: - Notification Handlers
@objc
private
func
didJoinedOfUid
()
{
let
videoCanvas
=
AgoraRtcVideoCanvas
()
videoCanvas
.
uid
=
playbackInfo
?
.
uid
??
0
...
...
@@ -413,7 +479,7 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
let
ret
=
YHPlayerManager
.
shared
.
agoraKit
.
setupRemoteVideo
(
videoCanvas
)
printLog
(
ret
)
}
@objc
private
func
didChatManagerReceiveMessages
(
_
note
:
Notification
)
{
guard
let
messages
=
note
.
object
as?
[
EMChatMessage
],
let
message
=
messages
.
first
,
...
...
@@ -429,7 +495,7 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
}
}
private
func
updateLiveDetailWith
(
event
:
YHChatRoomCustomEvent
)
{
viewModel
.
getLiveDetail
(
id
:
liveId
)
{
[
weak
self
]
liveDetail
,
error
in
guard
let
self
=
self
else
{
return
}
...
...
@@ -456,40 +522,45 @@ class YHLivePlayerViewController: YHBasePlayerViewController {
}
}
}
@objc
private
func
didLoginYH
()
{
if
YHLoginManager
.
shared
.
isLogin
()
{
joinLiveRoom
(
id
:
liveId
,
callback
:
{
_
,
_
in
})
}
}
@objc
private
func
didLogOutYH
()
{
//
}
@objc
private
func
didLoginEaseIMSuccess
()
{
if
let
roomId
=
roomId
{
joinChatRoom
(
roomId
:
roomId
)
}
}
@objc
private
func
didLogOutEaseIM
()
{
quitChatRoom
()
}
}
// MARK: - YHPlayerDelegate
extension
YHLivePlayerViewController
:
YHPlayerDelegate
{
func
player
(
_
player
:
YHPlayer
,
didChangedTo
positionMs
:
Int
,
atTimestamp
timestampMs
:
TimeInterval
)
{
DispatchQueue
.
main
.
async
{
//
}
}
func
player
(
_
player
:
YHPlayer
,
didChangedToState
state
:
AgoraMediaPlayerState
,
reason
:
AgoraMediaPlayerReason
)
{
DispatchQueue
.
main
.
async
{
// 更新通用UI状态
switch
state
{
case
.
playing
:
// controlView.updatePlayButton(isPlaying: true)
// 直播开始时的特殊处理
break
case
.
paused
,
.
stopped
:
// controlView.updatePlayButton(isPlaying: false)
// 直播开始时的特殊处理
break
case
.
failed
:
...
...
@@ -498,22 +569,11 @@ extension YHLivePlayerViewController: YHPlayerDelegate {
break
}
}
}
func
player
(
_
player
:
YHPlayer
,
didChangedToPosition
position
:
Int
)
{
let
duration
=
player
.
getDuration
()
guard
duration
>
0
else
{
return
}
let
progress
=
Float
(
position
)
/
Float
(
duration
)
let
currentTime
=
formatTime
(
position
)
let
totalTime
=
formatTime
(
duration
)
controlView
.
updateProgress
(
progress
,
currentTime
:
currentTime
,
totalTime
:
totalTime
)
}
}
func
player
(
_
player
:
YHPlayer
,
didReceiveVideoSize
size
:
CGSize
)
{
// 处理视频尺寸变化,如果需要的话
}
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/C/YHPlayer.swift
View file @
1b6dc0bc
...
...
@@ -6,119 +6,6 @@
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
//import AgoraRtcKit
//import Foundation
//
//// MARK: - 播放器类型
//
//enum YHPlayerType {
// case main
// case secondary
//}
//
//protocol YHPlayerDelegate: AnyObject {
// func player(_ player: YHPlayer, didChangedToState state: AgoraMediaPlayerState, reason: AgoraMediaPlayerReason)
// func player(_ player: YHPlayer, didChangedToPosition position: Int)
// func player(_ player: YHPlayer, didReceiveVideoSize size: CGSize)
//}
//
//// MARK: - 播放器实例封装
//
//class YHPlayer {
// weak var delegate: YHPlayerDelegate?
// let type: YHPlayerType
// var playerKit: AgoraRtcMediaPlayerProtocol?
// weak var agoraKit: AgoraRtcEngineKit?
//
// private(set) var currentURL: String?
// weak var currentPlayView: UIView?
// private(set) var currentTitle: String?
// private(set) var currentChannelId: String?
// private(set) var currentUid: UInt?
// private(set) var isJoined: Bool = false
//
// var isMuted: Bool {
// get { playerKit?.getMute() ?? false }
// set { playerKit?.mute(newValue) }
// }
//
// init(type: YHPlayerType, playerKit: AgoraRtcMediaPlayerProtocol?, agoraKit: AgoraRtcEngineKit?) {
// self.type = type
// self.playerKit = playerKit
// self.agoraKit = agoraKit
// // 基础设置
// playerKit?.setLoopCount(-1)
// }
//
// func setPlayView(_ view: UIView?) {
// currentPlayView = view
// playerKit?.setRenderMode(.fit)
// playerKit?.setView(view)
// }
//
// func setJoinInfo(channelId: String, uid: UInt) {
// currentChannelId = channelId
// currentUid = uid
// isJoined = true
// }
//
// func clearJoinInfo() {
// currentChannelId = nil
// currentUid = nil
// isJoined = false
// }
//
// func play(url: String, title: String? = nil) {
// currentURL = url
// currentTitle = title
// let mediaSource = AgoraMediaSource()
// mediaSource.url = url
// mediaSource.autoPlay = true
// let result = playerKit?.open(with: mediaSource)
// if result == 0 {
// playerKit?.play()
// }
// }
//
// func stop() {
// playerKit?.stop()
// currentPlayView = nil
// currentURL = nil
// currentTitle = nil
// }
//
// func pause() {
// playerKit?.pause()
// }
//
// func resume() {
// playerKit?.play()
// }
//
// func reset() {
// stop()
// setPlayView(nil)
// delegate = nil
// }
//
// func releasePlayer() {
// reset()
// playerKit = nil
// }
//
// func getPosition() -> Int {
// return playerKit?.getPosition() ?? 0
// }
//
// func getDuration() -> Int {
// return playerKit?.getDuration() ?? 0
// }
//
// func getPlayState() -> AgoraMediaPlayerState {
// return playerKit?.getPlayerState() ?? .idle
// }
//}
import
AgoraRtcKit
import
Foundation
...
...
@@ -132,6 +19,7 @@ protocol YHPlayerDelegate: AnyObject {
func
player
(
_
player
:
YHPlayer
,
didChangedToState
state
:
AgoraMediaPlayerState
,
reason
:
AgoraMediaPlayerReason
)
func
player
(
_
player
:
YHPlayer
,
didChangedToPosition
position
:
Int
)
func
player
(
_
player
:
YHPlayer
,
didReceiveVideoSize
size
:
CGSize
)
func
player
(
_
player
:
YHPlayer
,
didChangedTo
positionMs
:
Int
,
atTimestamp
timestampMs
:
TimeInterval
)
}
// MARK: - 播放器实例封装
...
...
@@ -234,10 +122,13 @@ class YHPlayer {
currentTitle
=
nil
}
func
play
(
url
:
String
,
title
:
String
?
=
nil
)
{
func
play
(
url
:
String
,
title
:
String
?
=
nil
,
view
:
UIView
?
)
{
currentURL
=
url
currentTitle
=
title
lastPlaybackInfo
=
(
url
,
title
)
// 保存播放信息
currentPlayView
=
view
playerKit
?
.
setRenderMode
(
.
fit
)
playerKit
?
.
setView
(
view
)
let
mediaSource
=
AgoraMediaSource
()
mediaSource
.
url
=
url
...
...
@@ -271,7 +162,7 @@ class YHPlayer {
func
resume
(
withNewView
view
:
UIView
)
{
// 设置新的播放视图
setPlayView
(
view
)
//
setPlayView(view)
// 如果有频道信息,通知 Manager 重新加入频道
if
let
token
=
currentToken
,
...
...
@@ -286,7 +177,7 @@ class YHPlayer {
// 如果有上次的播放信息,重新播放
if
let
lastInfo
=
lastPlaybackInfo
,
let
url
=
lastInfo
.
url
{
play
(
url
:
url
,
title
:
lastInfo
.
title
)
play
(
url
:
url
,
title
:
lastInfo
.
title
,
view
:
view
)
}
}
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/C/YHPlayerManager.swift
View file @
1b6dc0bc
...
...
@@ -106,7 +106,7 @@ class YHPlayerManager: NSObject {
if
let
view
=
view
{
player
.
setPlayView
(
view
)
}
player
.
play
(
url
:
url
,
title
:
title
)
player
.
play
(
url
:
url
,
title
:
title
,
view
:
view
)
}
func
pause
(
type
:
YHPlayerType
=
.
main
)
{
...
...
@@ -292,7 +292,7 @@ class YHPlayerManager: NSObject {
exitFloating
()
if
let
url
=
playbackInfo
.
url
{
player
.
play
(
url
:
url
,
title
:
playbackInfo
.
title
)
player
.
play
(
url
:
url
,
title
:
playbackInfo
.
title
,
view
:
playerVC
.
playerView
)
}
present
(
playerVC
,
from
:
sourceView
)
...
...
@@ -329,7 +329,7 @@ class YHPlayerManager: NSObject {
let
channelId
=
playbackInfo
.
channelId
,
let
uid
=
playbackInfo
.
uid
,
!
token
.
isEmpty
,
!
channelId
.
isEmpty
{
joinChannel
(
for
:
player
,
token
:
token
,
channelId
:
channelId
,
uid
:
uid
)
}
else
if
let
url
=
playbackInfo
.
url
,
url
.
count
>
0
{
player
.
play
(
url
:
url
,
title
:
playbackInfo
.
title
)
player
.
play
(
url
:
url
,
title
:
playbackInfo
.
title
,
view
:
playerVC
.
playerView
)
}
present
(
navVC
,
from
:
sourceView
)
...
...
@@ -339,32 +339,13 @@ class YHPlayerManager: NSObject {
guard
let
window
=
UIApplication
.
shared
.
yhKeyWindow
()
else
{
return
}
let
playerType
=
determinePlayerType
(
for
:
.
floating
)
let
player
:
YHPlayer
//
= player(for: playerType)
let
player
:
YHPlayer
=
player
(
for
:
playerType
)
var
updatedInfo
=
playbackInfo
updatedInfo
.
scene
=
.
floating
updatedInfo
.
playerType
=
playerType
currentPlaybackInfo
[
playerType
]
=
updatedInfo
// 检查是否存在当前播放器
if
let
existingPlayer
=
activePlayers
[
playerType
],
currentPlaybackInfo
[
playerType
]
==
playbackInfo
{
// 使用现有播放器
player
=
existingPlayer
}
else
{
// 创建新播放器
player
=
self
.
player
(
for
:
playerType
)
// 加入频道
if
let
token
=
playbackInfo
.
token
,
let
channelId
=
playbackInfo
.
channelId
,
let
uid
=
playbackInfo
.
uid
,
!
token
.
isEmpty
,
!
channelId
.
isEmpty
{
joinChannel
(
for
:
player
,
token
:
token
,
channelId
:
channelId
,
uid
:
uid
)
}
else
if
let
url
=
playbackInfo
.
url
,
!
url
.
isEmpty
{
player
.
play
(
url
:
url
,
title
:
playbackInfo
.
title
)
}
}
// // 加入频道
// if let token = playbackInfo.token,
// let channelId = playbackInfo.channelId, let uid = playbackInfo.uid, !token.isEmpty, !channelId.isEmpty {
...
...
@@ -392,6 +373,15 @@ class YHPlayerManager: NSObject {
// 计算目标位置
let
targetFrame
=
floatingWindow
.
calculateInitialFrame
()
// 检查是否存在当前播放器
// 加入频道
if
let
token
=
playbackInfo
.
token
,
let
channelId
=
playbackInfo
.
channelId
,
let
uid
=
playbackInfo
.
uid
,
!
token
.
isEmpty
,
!
channelId
.
isEmpty
{
joinChannel
(
for
:
player
,
token
:
token
,
channelId
:
channelId
,
uid
:
uid
)
}
else
if
let
url
=
playbackInfo
.
url
,
!
url
.
isEmpty
{
player
.
play
(
url
:
url
,
title
:
playbackInfo
.
title
,
view
:
floatingWindow
.
contentView
)
}
// 执行动画
let
showFloatingWindow
=
{
...
...
@@ -417,6 +407,14 @@ class YHPlayerManager: NSObject {
floatingWindow
.
player
=
player
floatingWindow
.
playbackInfo
=
updatedInfo
self
.
floatingWindow
=
floatingWindow
// 检查是否存在当前播放器
if
let
token
=
playbackInfo
.
token
,
let
channelId
=
playbackInfo
.
channelId
,
let
uid
=
playbackInfo
.
uid
,
!
token
.
isEmpty
,
!
channelId
.
isEmpty
{
joinChannel
(
for
:
player
,
token
:
token
,
channelId
:
channelId
,
uid
:
uid
)
}
else
if
let
url
=
playbackInfo
.
url
,
!
url
.
isEmpty
{
player
.
play
(
url
:
url
,
title
:
playbackInfo
.
title
,
view
:
floatingWindow
.
contentView
)
}
let
showFloatingWindow
=
{
floatingWindow
.
show
(
in
:
window
)
...
...
@@ -448,7 +446,7 @@ class YHPlayerManager: NSObject {
let
channelId
=
playbackInfo
.
channelId
,
let
uid
=
playbackInfo
.
uid
,
!
token
.
isEmpty
,
!
channelId
.
isEmpty
{
joinChannel
(
for
:
player
,
token
:
token
,
channelId
:
channelId
,
uid
:
uid
)
}
else
if
let
url
=
playbackInfo
.
url
,
!
url
.
isEmpty
{
player
.
play
(
url
:
url
,
title
:
playbackInfo
.
title
)
player
.
play
(
url
:
url
,
title
:
playbackInfo
.
title
,
view
:
view
)
}
}
...
...
@@ -487,6 +485,12 @@ extension YHPlayerManager: AgoraRtcMediaPlayerDelegate {
player
.
delegate
?
.
player
(
player
,
didChangedToPosition
:
position
)
}
}
func
AgoraRtcMediaPlayer
(
_
playerKit
:
any
AgoraRtcMediaPlayerProtocol
,
didChangedTo
positionMs
:
Int
,
atTimestamp
timestampMs
:
TimeInterval
)
{
if
let
player
=
activePlayers
.
values
.
first
(
where
:
{
$0
.
playerKit
===
playerKit
})
{
player
.
delegate
?
.
player
(
player
,
didChangedTo
:
positionMs
,
atTimestamp
:
timestampMs
)
}
}
func
AgoraRtcMediaPlayer
(
_
playerKit
:
AgoraRtcMediaPlayerProtocol
,
infoUpdated
info
:
AgoraMediaPlayerUpdatedInfo
)
{
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/C/YHVODPlayerViewController.swift
View file @
1b6dc0bc
...
...
@@ -6,27 +6,26 @@
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
// YHVODPlayerViewController.swift
import
UIKit
import
AgoraRtcKit
import
UIKit
class
YHVODPlayerViewController
:
YHBasePlayerViewController
{
// MARK: - Properties
private
let
vodId
:
Int
var
startPosition
:
Int
=
0
private
let
viewModel
=
YHLiveSalesViewModel
()
private
lazy
var
dropdownView
:
YHCategoryDropdownView
=
{
let
view
=
YHCategoryDropdownView
()
view
.
onSelect
=
{
category
in
print
(
"Selected:
\(
category
)
"
)
}
private
var
goodsListView
:
YHLiveShopView
?
private
lazy
var
progressControl
:
YHVideoProgressControl
=
{
let
view
=
YHVideoProgressControl
()
return
view
}()
// MARK: - Initialization
init
(
id
:
Int
,
url
:
String
?
=
nil
,
title
:
String
?
=
nil
)
{
self
.
vodId
=
id
vodId
=
id
super
.
init
(
nibName
:
nil
,
bundle
:
nil
)
player
?
.
delegate
=
self
currentPlayingURL
=
url
...
...
@@ -35,42 +34,74 @@ class YHVODPlayerViewController: YHBasePlayerViewController {
play
(
url
:
url
,
title
:
title
)
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
func
play
(
url
:
String
,
title
:
String
?
=
nil
)
{
currentPlayingURL
=
url
currentVideoTitle
=
title
controlView
.
setTitle
(
title
??
""
)
//
controlView.setTitle(title ?? "")
YHPlayerManager
.
shared
.
play
(
url
:
url
,
inView
:
playerView
,
title
:
title
)
}
// MARK: - Lifecycle
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
//
setupUI()
setupUI
()
loadVideoDetail
()
controlView
.
isHidden
=
true
//
controlView.isHidden = true
}
// MARK: - SetupView
private
func
setupUI
()
{
containerView
.
addSubview
(
dropdownView
)
dropdownView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
topBarView
.
snp
.
bottom
)
.
offset
(
24
)
make
.
left
.
equalToSuperview
()
.
offset
(
16
)
make
.
width
.
equalTo
(
56
)
containerView
.
addSubview
(
progressControl
)
progressControl
.
snp
.
makeConstraints
{
make
in
make
.
left
.
right
.
bottom
.
equalToSuperview
()
make
.
top
.
equalTo
(
view
.
safeAreaLayoutGuide
.
snp
.
bottom
)
.
offset
(
-
102
)
}
topBarView
.
closeButtonClickEvent
=
{
[
weak
self
]
in
self
?
.
closeLive
()
}
topBarView
.
zoomButtonClickEvent
=
{
[
weak
self
]
in
self
?
.
enterFloating
()
}
topBarView
.
shareButtonClickEvent
=
{
[
weak
self
]
in
self
?
.
shareLive
()
}
}
func
enterFloating
()
{
guard
let
playbackInfo
=
playbackInfo
else
{
return
}
YHPlayerManager
.
shared
.
enterFloating
(
from
:
self
,
playbackInfo
:
playbackInfo
)
}
private
func
closeLive
()
{
YHPlayerManager
.
shared
.
stop
(
type
:
.
main
)
dismiss
(
animated
:
true
)
}
private
func
shareLive
()
{
guard
let
recordedDetailModel
=
viewModel
.
recordedDetailModel
else
{
return
}
YHShareAlertView
.
show
(
image
:
recordedDetailModel
.
recorded_image
,
title
:
"@"
+
recordedDetailModel
.
account
,
subMessage
:
recordedDetailModel
.
recorded_title
,
linkUrl
:
recordedDetailModel
.
recorded_h5_url
,
isLive
:
false
)
}
// MARK: - Data Loading
private
func
loadVideoDetail
()
{
viewModel
.
getRecordedDetail
(
id
:
vodId
)
{
[
weak
self
]
recordedDetail
,
error
in
guard
let
self
=
self
else
{
return
}
if
let
recordedDetail
=
recordedDetail
{
self
.
handleVideoDetailSuccess
(
recordedDetail
)
}
else
{
...
...
@@ -79,9 +110,9 @@ class YHVODPlayerViewController: YHBasePlayerViewController {
YHHUD
.
flash
(
message
:
errorMsg
)
}
}
}
}
}
private
func
handleVideoDetailSuccess
(
_
detail
:
YHRecordedDetailModel
)
{
// 更新顶部栏信息
topBarView
.
setupTopBarView
(
...
...
@@ -90,60 +121,198 @@ class YHVODPlayerViewController: YHBasePlayerViewController {
count
:
detail
.
access_num
)
// 如果没有预设URL,使用接口返回的URL播放
if
currentPlayingURL
==
nil
{
play
(
url
:
detail
.
recorded_url
,
title
:
nil
)
if
currentPlayingURL
==
nil
,
detail
.
recorded_url
.
count
>
0
{
playbackInfo
?
.
url
=
detail
.
recorded_url
playbackInfo
?
.
title
=
detail
.
recorded_title
play
(
url
:
detail
.
recorded_url
,
title
:
detail
.
recorded_title
)
}
progressControl
.
configure
(
with
:
detail
.
recordedVideoSlice
.
compactMap
{
$0
.
tag
})
progressControl
.
onPlayStatusChanged
=
{
[
weak
self
]
isPlaying
in
printLog
(
"播放状态:
\(
isPlaying
)
"
)
if
isPlaying
{
self
?
.
player
?
.
resume
()
}
else
{
self
?
.
player
?
.
pause
()
}
}
// 选择片段回调
progressControl
.
onSegmentSelected
=
{
[
weak
self
]
index
in
printLog
(
"选择片段:
\(
index
)
"
)
guard
detail
.
recordedVideoSlice
.
count
>
index
else
{
return
}
let
item
=
detail
.
recordedVideoSlice
[
index
]
self
?
.
player
?
.
seek
(
to
:
item
.
start_second
*
1000
)
}
// 时间改变回调
progressControl
.
onTimeChanged
=
{
[
weak
self
]
time
in
printLog
(
"跳转到:
\(
time
)
秒"
)
self
?
.
player
?
.
seek
(
to
:
Int
(
time
*
1000.0
))
}
progressControl
.
updateGiftCount
(
detail
.
goods
.
count
)
progressControl
.
giftButtonClickEvent
=
{
[
weak
self
]
in
self
?
.
showGoods
()
}
dropdownView
.
configure
(
with
:
detail
.
recordedVideoCate
.
compactMap
{
$0
.
name
})
}
private
func
showGoods
()
{
let
list
=
viewModel
.
recordedDetailModel
?
.
goods
??
[]
let
view
=
YHLiveShopView
.
show
{
[
weak
self
]
index
in
guard
list
.
count
>
index
else
{
return
}
let
model
=
list
[
index
]
self
?
.
gotoH5GoodsDetail
(
id
:
model
.
id
)
}
view
.
dataSource
=
list
view
.
closeEvent
=
{
[
weak
self
]
in
self
?
.
goodsListView
=
nil
}
view
.
buyData
=
{
[
weak
self
]
index
in
guard
list
.
count
>
index
else
{
return
}
let
model
=
list
[
index
]
self
?
.
createOrder
(
id
:
model
.
id
)
}
goodsListView
=
view
}
private
func
createOrder
(
id
:
Int
)
{
YHHUD
.
show
(
.
progress
(
message
:
"加载中..."
))
viewModel
.
createOrder
(
source
:
2
,
sourceId
:
vodId
,
productId
:
id
)
{
[
weak
self
]
orderModel
,
error
in
YHHUD
.
hide
()
guard
let
self
=
self
else
{
return
}
guard
let
orderModel
=
orderModel
else
{
if
let
errorMsg
=
error
?
.
errorMsg
,
errorMsg
.
count
>
0
{
YHHUD
.
flash
(
message
:
errorMsg
)
}
return
}
var
url
=
YHBaseUrlManager
.
shared
.
curH5URL
()
+
"superAppBridge.html#/order/order-confirm"
+
"?id=
\(
orderModel
.
id
)
"
if
YHLoginManager
.
shared
.
isLogin
()
{
let
token
=
YHLoginManager
.
shared
.
h5Token
let
urlHasParam
=
String
.
hasQueryParameters
(
urlString
:
url
)
if
urlHasParam
{
url
=
url
+
"¶m="
+
token
}
else
{
url
=
url
+
"?param="
+
token
}
}
var
tUrl
=
url
if
!
url
.
contains
(
"navigationH="
)
{
tUrl
=
url
+
"?navigationH=
\(
k_Height_NavigationtBarAndStatuBar
)
"
if
url
.
contains
(
"?"
)
{
tUrl
=
url
+
"&navigationH=
\(
k_Height_NavigationtBarAndStatuBar
)
"
}
}
let
vc
=
YHH5WebViewVC
()
vc
.
url
=
tUrl
vc
.
isHideNavigationBar
=
false
goodsListView
?
.
dismiss
()
navigationController
?
.
pushViewController
(
vc
)
}
}
private
func
gotoH5GoodsDetail
(
id
:
Int
)
{
var
url
=
YHBaseUrlManager
.
shared
.
curH5URL
()
+
"superAppBridge.html#/goods/sales-detail"
+
"?id=
\(
id
)
"
if
YHLoginManager
.
shared
.
isLogin
()
{
let
token
=
YHLoginManager
.
shared
.
h5Token
let
urlHasParam
=
String
.
hasQueryParameters
(
urlString
:
url
)
if
urlHasParam
{
url
=
url
+
"¶m="
+
token
}
else
{
url
=
url
+
"?param="
+
token
}
}
var
tUrl
=
url
if
!
url
.
contains
(
"navigationH="
)
{
tUrl
=
url
+
"?navigationH=
\(
k_Height_NavigationtBarAndStatuBar
)
"
if
url
.
contains
(
"?"
)
{
tUrl
=
url
+
"&navigationH=
\(
k_Height_NavigationtBarAndStatuBar
)
"
}
}
let
vc
=
YHH5WebViewVC
()
vc
.
url
=
tUrl
vc
.
isHideNavigationBar
=
false
goodsListView
?
.
dismiss
()
navigationController
?
.
pushViewController
(
vc
)
}
}
// MARK: - YHPlayerDelegate
extension
YHVODPlayerViewController
:
YHPlayerDelegate
{
func
player
(
_
player
:
YHPlayer
,
didChangedTo
positionMs
:
Int
,
atTimestamp
timestampMs
:
TimeInterval
)
{
DispatchQueue
.
main
.
async
{
self
.
updateProgressControl
(
player
,
position
:
positionMs
)
}
}
func
player
(
_
player
:
YHPlayer
,
didChangedToState
state
:
AgoraMediaPlayerState
,
reason
:
AgoraMediaPlayerReason
)
{
switch
state
{
case
.
playing
:
controlView
.
updatePlayButton
(
isPlaying
:
true
)
updatePlayCount
()
case
.
paused
,
.
stopped
:
controlView
.
updatePlayButton
(
isPlaying
:
false
)
case
.
failed
:
showAlert
(
message
:
"播放失败,错误原因:
\(
reason
.
rawValue
)
"
)
default
:
break
}
}
DispatchQueue
.
main
.
async
{
switch
state
{
case
.
opening
:
printLog
(
"####.opening:
\(
player
.
getDuration
()
)
"
)
case
.
openCompleted
:
self
.
updateProgressControl
(
player
,
position
:
player
.
getPosition
())
printLog
(
"####.openCompleted:
\(
player
.
getDuration
()
)
"
)
case
.
playing
:
self
.
progressControl
.
setPlaying
(
true
)
printLog
(
"####.playing:
\(
player
.
getDuration
()
)
"
)
case
.
paused
,
.
stopped
:
self
.
progressControl
.
setPlaying
(
false
)
case
.
failed
:
self
.
showAlert
(
message
:
"播放失败,错误原因:
\(
reason
.
rawValue
)
"
)
default
:
break
}
}
}
func
player
(
_
player
:
YHPlayer
,
didChangedToPosition
position
:
Int
)
{
let
duration
=
player
.
getDuration
()
// playerKit.getDuration()
guard
duration
>
0
else
{
return
}
let
progress
=
Float
(
position
)
/
Float
(
duration
)
let
currentTime
=
formatTime
(
position
)
let
totalTime
=
formatTime
(
duration
)
controlView
.
updateProgress
(
progress
,
currentTime
:
currentTime
,
totalTime
:
totalTime
)
}
DispatchQueue
.
main
.
async
{
self
.
updateProgressControl
(
player
,
position
:
position
)
}
}
func
player
(
_
player
:
YHPlayer
,
didReceiveVideoSize
size
:
CGSize
)
{
// 处理视频尺寸变化,如有需要
DispatchQueue
.
main
.
async
{
//
}
}
}
// MARK: - Helper Methods
private
extension
YHVODPlayerViewController
{
func
updatePlayCount
()
{
// YHAPIService.shared.updateVideoPlayCount(id: vodId) { [weak self] result in
// switch result {
// case .success:
// break
// case .failure(let error):
// printLog("更新播放次数失败: \(error)")
// }
// }
private
func
updateProgressControl
(
_
player
:
YHPlayer
,
position
:
Int
)
{
let
duration
=
player
.
getDuration
()
guard
duration
>
0
else
{
return
}
var
currentIndex
:
Int
?
if
let
recordedVideoSlice
=
viewModel
.
recordedDetailModel
?
.
recordedVideoSlice
,
recordedVideoSlice
.
count
>
0
{
let
lastIndex
=
recordedVideoSlice
.
count
-
1
recordedVideoSlice
.
enumerated
()
.
forEach
{
index
,
item
in
if
position
>=
item
.
start_second
*
1000
,
position
<=
item
.
end_second
*
1000
{
currentIndex
=
index
return
}
else
if
index
==
lastIndex
,
position
>=
item
.
end_second
*
1000
{
currentIndex
=
index
return
}
else
if
position
>
item
.
end_second
*
1000
,
index
+
1
<
lastIndex
{
let
next
=
recordedVideoSlice
[
index
+
1
]
if
position
<
next
.
start_second
*
1000
{
currentIndex
=
index
return
}
}
else
if
position
<=
recordedVideoSlice
[
0
]
.
start_second
*
1000
{
currentIndex
=
0
return
}
}
}
progressControl
.
updateTime
(
Double
(
position
)
/
1000.0
,
duration
:
Double
(
duration
)
/
1000.0
,
currentIndex
:
currentIndex
)
}
}
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/IM(环信)/YHIMHelper.swift
View file @
1b6dc0bc
...
...
@@ -22,6 +22,11 @@ enum YHChatRoomCustomEvent: String {
case
liveGoodsRefresh
=
"chatRoomCustomEventLiveGoodsRefresh"
}
struct
YHChatRoomCustomLocal
{
static
let
tipsEvent
=
"YHLiveRoomTips"
static
let
tipsKey
=
"tips"
}
class
YHIMHelper
:
NSObject
{
static
let
didLoginEaseIMSuccess
=
Notification
.
Name
(
"com.YHIMHelper.didLoginEaseIMSuccess"
)
static
let
didLogOutEaseIM
=
Notification
.
Name
(
"com.YHIMHelper.didLogOutEaseIM"
)
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/M/YHLiveCreateOrderModel.swift
0 → 100644
View file @
1b6dc0bc
//
// YHLiveCreateOrderModel.swift
// galaxy
//
// Created by alexzzw on 2024/12/4.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import
Foundation
import
SmartCodable
class
YHLiveCreateOrderModel
:
SmartCodable
{
var
id
:
Int
=
0
required
init
()
{
}
}
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/M/YHLiveDetailModel.swift
View file @
1b6dc0bc
...
...
@@ -75,6 +75,7 @@ class YHLiveGoodsItem: SmartCodable {
var
linePrice
:
String
=
""
var
sn
:
String
=
""
var
banner
:
String
=
""
var
flag
:
Int
=
0
required
init
()
{
}
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/M/YHRecordedDetailModel.swift
View file @
1b6dc0bc
...
...
@@ -14,9 +14,11 @@ class YHRecordedDetailModel: SmartCodable {
var
avatar
:
String
=
""
var
access_num
:
Int
=
0
var
tips
:
String
=
""
var
subject
:
String
=
""
var
recorded_url
:
String
=
""
var
recorded_cover
:
String
=
""
var
recorded_image
:
String
=
""
var
recorded_title
:
String
=
""
var
recorded_h5_url
:
String
=
""
var
goods
:
[
YHLiveGoodsItem
]
=
[]
var
recordedVideoCate
:
[
YHRecordedVideoCategoryItem
]
=
[]
var
recordedVideoSlice
:
[
YHRecordedVideoSliceItem
]
=
[]
...
...
@@ -34,8 +36,8 @@ class YHRecordedVideoCategoryItem: SmartCodable {
}
class
YHRecordedVideoSliceItem
:
SmartCodable
{
var
start
Second
:
String
=
""
var
end
Second
:
String
=
""
var
start
_second
:
Int
=
0
var
end
_second
:
Int
=
0
var
tag
:
String
=
""
var
index
:
Int
=
0
...
...
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/V/YHLiveMessageCell.swift
View file @
1b6dc0bc
...
...
@@ -67,4 +67,10 @@ class YHLiveMessageCell: UITableViewCell {
let
contentAtt
=
ASAttributedString
(
string
:
content
,
.
foreground
(
UIColor
.
white
),
.
font
(
UIFont
.
PFSC_R
(
ofSize
:
13
)))
contentLabel
.
attributed
.
text
=
nickAtt
+
contentAtt
}
func
configureTipsMessage
(
_
tips
:
String
)
{
let
tipsIcon
=
ASAttributedString
.
init
(
.
image
(
UIImage
(
named
:
"live_msg_tips_icon"
)
??
UIImage
(),
.
custom
(
.
offset
(
CGPoint
(
x
:
0
,
y
:
-
4.0
)),
size
:
.
init
(
width
:
32
,
height
:
18
))))
let
contentAtt
=
(
tipsIcon
+
ASAttributedString
(
string
:
tips
,
.
foreground
(
UIColor
.
white
),
.
font
(
UIFont
.
PFSC_R
(
ofSize
:
13
))))
contentLabel
.
attributed
.
text
=
contentAtt
}
}
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/V/YHLiveMessageListView.swift
View file @
1b6dc0bc
...
...
@@ -107,8 +107,11 @@ extension YHLiveMessageListView: UITableViewDelegate, UITableViewDataSource {
printLog
(
body
.
text
)
printLog
(
"
\(
nickName
)
:
\(
body
.
text
)
"
)
content
=
body
.
text
cell
.
configureNormalMessage
(
nickName
,
content
)
}
else
if
let
body
=
message
.
body
as?
EMCustomMessageBody
,
body
.
event
==
YHChatRoomCustomLocal
.
tipsEvent
,
let
customExt
=
body
.
customExt
,
let
tips
=
customExt
[
YHChatRoomCustomLocal
.
tipsKey
]
{
cell
.
configureTipsMessage
(
tips
)
}
cell
.
configureNormalMessage
(
nickName
,
content
)
return
cell
}
}
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/V/YHLiveShopView.swift
View file @
1b6dc0bc
...
...
@@ -12,6 +12,7 @@ import AttributedString
class
YHLiveShopView
:
UIView
{
var
closeEvent
:
(()
->
Void
)?
var
backData
:
((
Int
)
->
Void
)?
var
buyData
:
((
Int
)
->
Void
)?
var
centerView
:
UIView
!
var
titleLabel
:
UILabel
!
var
subTitleLabel
:
UILabel
!
...
...
@@ -175,7 +176,11 @@ extension YHLiveShopView: UITableViewDelegate, UITableViewDataSource {
}
let
model
=
dataSource
[
indexPath
.
row
]
let
cell
=
tableView
.
dequeueReusableCell
(
withClass
:
YHLiveShopViewCell
.
self
)
model
.
flag
=
indexPath
.
row
+
1
cell
.
dataSource
=
model
cell
.
buyEvent
=
{
[
weak
self
]
in
self
?
.
buyData
?(
indexPath
.
row
)
}
return
cell
}
...
...
@@ -218,7 +223,10 @@ class YHLiveShopViewCell: UITableViewCell {
var
subPriceLabel
:
UILabel
!
var
flagLabel
:
UILabel
!
var
buyButton
:
UIButton
!
var
addButton
:
UIButton
!
//var addButton: UIButton!
// var addEvent: (() -> Void)?
var
buyEvent
:
(()
->
Void
)?
var
dataSource
:
YHLiveGoodsItem
=
YHLiveGoodsItem
()
{
didSet
{
...
...
@@ -234,6 +242,7 @@ class YHLiveShopViewCell: UITableViewCell {
priceLabel
.
attributed
.
text
=
a
+
b
let
c
:
ASAttributedString
=
.
init
(
"
\(
dataSource
.
price
)
"
,
.
font
(
UIFont
.
PFSC_R
(
ofSize
:
14
)),
.
foreground
(
UIColor
(
hex
:
0x8993a2
)),
.
strikethrough
(
.
single
))
subPriceLabel
.
attributed
.
text
=
c
flagLabel
.
text
=
"
\(
dataSource
.
flag
)
"
}
}
override
func
awakeFromNib
()
{
...
...
@@ -305,9 +314,6 @@ class YHLiveShopViewCell: UITableViewCell {
priceLabel
=
{
let
view
=
UILabel
()
// let a: ASAttributedString = .init("¥", .font(UIFont.PFSC_R(ofSize: 14)),.foreground(UIColor.mainTextColor))
// let b: ASAttributedString = .init("61000", .font(UIFont.PFSC_R(ofSize: 20)),.foreground(UIColor.mainTextColor))
// view.attributed.text = a + b
return
view
}()
contentView
.
addSubview
(
priceLabel
)
...
...
@@ -320,8 +326,6 @@ class YHLiveShopViewCell: UITableViewCell {
subPriceLabel
=
{
let
view
=
UILabel
()
// let c: ASAttributedString = .init("¥61000", .font(UIFont.PFSC_R(ofSize: 14)),.foreground(UIColor(hex:0x8993a2)), .strikethrough(.single))
// view.attributed.text = c
return
view
}()
contentView
.
addSubview
(
subPriceLabel
)
...
...
@@ -334,7 +338,6 @@ class YHLiveShopViewCell: UITableViewCell {
flagLabel
=
{
let
label
=
UILabel
()
label
.
text
=
"1"
label
.
textAlignment
=
.
center
label
.
textColor
=
.
white
label
.
font
=
UIFont
.
PFSC_M
(
ofSize
:
10
)
...
...
@@ -366,28 +369,30 @@ class YHLiveShopViewCell: UITableViewCell {
make
.
height
.
equalTo
(
28
)
}
addButton
=
{
let
button
=
UIButton
(
type
:
.
custom
)
button
.
backgroundColor
=
UIColor
(
hex
:
0xebf0f9
)
button
.
setImage
(
UIImage
(
named
:
"live_shop_add"
),
for
:
.
normal
)
button
.
contentHorizontalAlignment
=
.
center
button
.
addTarget
(
self
,
action
:
#selector(
add
)
,
for
:
.
touchUpInside
)
return
button
}()
contentView
.
addSubview
(
addButton
)
addButton
.
snp
.
makeConstraints
{
make
in
make
.
right
.
equalTo
(
-
88
)
make
.
width
.
equalTo
(
46
)
make
.
bottom
.
equalTo
(
centerImageView
.
snp
.
bottom
)
make
.
height
.
equalTo
(
28
)
}
//
addButton = {
//
let button = UIButton(type: .custom)
//
button.backgroundColor = UIColor(hex: 0xebf0f9)
//
button.setImage(UIImage(named: "live_shop_add"), for: .normal)
//
button.contentHorizontalAlignment = .center
//
button.addTarget(self, action: #selector(add), for: .touchUpInside)
//
return button
//
}()
//
contentView.addSubview(addButton)
//
addButton.snp.makeConstraints { make in
//
make.right.equalTo(-88)
//
make.width.equalTo(46)
//
make.bottom.equalTo(centerImageView.snp.bottom)
//
make.height.equalTo(28)
//
}
}
@objc
func
add
()
{
//YHHUD.flash(message: "已加入购物车")
}
// @objc func add() {
// addEvent?()
// //YHHUD.flash(message: "已加入购物车")
// }
@objc
func
buy
()
{
buyEvent
?()
//YHHUD.flash(message: "已买")
}
}
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/V/YHVideoProgressControl.swift
0 → 100644
View file @
1b6dc0bc
//
// YHVideoProgressControl.swift
// galaxy
//
// Created by alexzzw on 2024/12/4.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import
UIKit
class
YHVideoProgressControl
:
UIView
{
// MARK: - UI Components
private
lazy
var
segmentCollection
:
UICollectionView
=
{
let
layout
=
UICollectionViewFlowLayout
()
layout
.
scrollDirection
=
.
horizontal
layout
.
minimumLineSpacing
=
4
layout
.
minimumInteritemSpacing
=
4
let
collection
=
UICollectionView
(
frame
:
.
zero
,
collectionViewLayout
:
layout
)
collection
.
backgroundColor
=
.
clear
collection
.
showsHorizontalScrollIndicator
=
false
collection
.
register
(
SegmentCell
.
self
,
forCellWithReuseIdentifier
:
"SegmentCell"
)
collection
.
delegate
=
self
collection
.
dataSource
=
self
collection
.
contentInset
=
UIEdgeInsets
(
top
:
0
,
left
:
0
,
bottom
:
0
,
right
:
0
)
collection
.
allowsSelection
=
true
collection
.
delaysContentTouches
=
false
return
collection
}()
private
lazy
var
progressSlider
:
UISlider
=
{
let
slider
=
UISlider
()
slider
.
minimumTrackTintColor
=
.
white
slider
.
maximumTrackTintColor
=
.
white
.
withAlphaComponent
(
0.24
)
slider
.
setThumbImage
(
UIImage
(
named
:
"live_slider_thumb"
),
for
:
.
normal
)
slider
.
addTarget
(
self
,
action
:
#selector(
sliderValueChanged
)
,
for
:
.
valueChanged
)
return
slider
}()
private
lazy
var
playButton
:
UIButton
=
{
let
button
=
UIButton
(
type
:
.
custom
)
button
.
setImage
(
UIImage
(
named
:
"live_icon_play"
),
for
:
.
normal
)
button
.
setImage
(
UIImage
(
named
:
"live_icon_pause"
),
for
:
.
selected
)
button
.
addTarget
(
self
,
action
:
#selector(
playButtonTapped
)
,
for
:
.
touchUpInside
)
return
button
}()
private
lazy
var
currentTimeLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
textColor
=
.
white
label
.
font
=
.
PFSC_R
(
ofSize
:
12
)
return
label
}()
private
lazy
var
timeSeparator
:
UIImageView
=
{
let
imageView
=
UIImageView
(
image
:
UIImage
(
named
:
"live_time_separator"
))
return
imageView
}()
private
lazy
var
totalTimeLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
textColor
=
.
white
.
withAlphaComponent
(
0.70
)
label
.
font
=
.
PFSC_R
(
ofSize
:
12
)
return
label
}()
private
lazy
var
giftButton
:
UIButton
=
{
let
button
=
UIButton
(
type
:
.
custom
)
button
.
setBackgroundImage
(
UIImage
(
named
:
"live_room_msg_gift"
),
for
:
.
normal
)
button
.
setTitle
(
"0"
,
for
:
.
normal
)
button
.
setTitleColor
(
UIColor
.
white
,
for
:
.
normal
)
button
.
titleLabel
?
.
font
=
.
PFSC_M
(
ofSize
:
10
)
button
.
addTarget
(
self
,
action
:
#selector(
giftButtonTapped
)
,
for
:
.
touchUpInside
)
button
.
titleEdgeInsets
=
UIEdgeInsets
(
top
:
5
,
left
:
0
,
bottom
:
-
5
,
right
:
0
)
return
button
}()
private
lazy
var
bottomVisualEffectView
:
UIVisualEffectView
=
{
let
effect
=
UIBlurEffect
(
style
:
.
dark
)
let
view
=
UIVisualEffectView
(
effect
:
effect
)
view
.
alpha
=
0.9
return
view
}()
// MARK: - Properties
private
var
segments
:
[
String
]
=
[]
private
var
currentSegmentIndex
=
0
private
var
isPlaying
=
false
private
var
currentTime
:
TimeInterval
=
0
private
var
duration
:
TimeInterval
=
0
var
onPlayStatusChanged
:
((
Bool
)
->
Void
)?
var
onSegmentSelected
:
((
Int
)
->
Void
)?
var
onTimeChanged
:
((
TimeInterval
)
->
Void
)?
var
giftButtonClickEvent
:
(()
->
Void
)?
// MARK: - Initialization
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
setupUI
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
// MARK: - UI Setup
private
func
setupUI
()
{
addSubview
(
bottomVisualEffectView
)
addSubview
(
segmentCollection
)
addSubview
(
progressSlider
)
addSubview
(
playButton
)
addSubview
(
currentTimeLabel
)
addSubview
(
timeSeparator
)
addSubview
(
totalTimeLabel
)
addSubview
(
giftButton
)
bottomVisualEffectView
.
frame
=
CGRect
(
x
:
0
,
y
:
0
,
width
:
bounds
.
size
.
width
,
height
:
bounds
.
size
.
height
)
bottomVisualEffectView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
left
.
right
.
equalToSuperview
()
make
.
height
.
equalToSuperview
()
}
// 渐变效果
let
gradinetLayer
=
CAGradientLayer
()
gradinetLayer
.
colors
=
[
UIColor
.
black
.
withAlphaComponent
(
0
)
.
cgColor
,
UIColor
.
black
.
withAlphaComponent
(
0
)
.
cgColor
,
UIColor
.
black
.
withAlphaComponent
(
0.16
)
.
cgColor
,
UIColor
.
black
.
withAlphaComponent
(
0.16
)
.
cgColor
]
gradinetLayer
.
startPoint
=
CGPoint
(
x
:
0.5
,
y
:
0
)
gradinetLayer
.
endPoint
=
CGPoint
(
x
:
0.5
,
y
:
1
)
gradinetLayer
.
frame
=
bottomVisualEffectView
.
bounds
bottomVisualEffectView
.
layer
.
mask
=
gradinetLayer
segmentCollection
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalToSuperview
()
.
offset
(
16
)
make
.
left
.
equalToSuperview
()
.
offset
(
16
)
make
.
height
.
equalTo
(
20
)
make
.
right
.
equalToSuperview
()
.
offset
(
-
4
)
}
progressSlider
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
16
)
make
.
right
.
equalToSuperview
()
.
offset
(
-
16
)
make
.
top
.
equalTo
(
segmentCollection
.
snp
.
bottom
)
.
offset
(
8
)
}
playButton
.
contentEdgeInsets
=
UIEdgeInsets
(
top
:
8
,
left
:
8
,
bottom
:
8
,
right
:
8
)
playButton
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
8
)
make
.
top
.
equalTo
(
progressSlider
.
snp
.
bottom
)
.
offset
(
12
)
make
.
size
.
equalTo
(
CGSize
(
width
:
32
,
height
:
32
))
}
currentTimeLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalTo
(
playButton
.
snp
.
right
)
.
offset
(
5
)
make
.
centerY
.
equalTo
(
playButton
)
}
timeSeparator
.
snp
.
makeConstraints
{
make
in
make
.
centerY
.
equalTo
(
playButton
)
make
.
left
.
equalTo
(
currentTimeLabel
.
snp
.
right
)
.
offset
(
8
)
make
.
size
.
equalTo
(
CGSize
(
width
:
4
,
height
:
11
))
}
totalTimeLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalTo
(
timeSeparator
.
snp
.
right
)
.
offset
(
8
)
make
.
centerY
.
equalTo
(
playButton
)
}
giftButton
.
snp
.
makeConstraints
{
make
in
make
.
right
.
equalToSuperview
()
.
offset
(
-
16
)
make
.
centerY
.
equalTo
(
playButton
)
make
.
width
.
height
.
equalTo
(
38
)
}
}
// MARK: - Public Methods
func
configure
(
with
segments
:
[
String
])
{
self
.
segments
=
segments
segmentCollection
.
reloadData
()
}
func
updateTime
(
_
current
:
TimeInterval
,
duration
:
TimeInterval
,
currentIndex
:
Int
?
=
nil
)
{
self
.
currentTime
=
current
self
.
duration
=
duration
progressSlider
.
value
=
Float
(
current
/
duration
)
currentTimeLabel
.
text
=
String
(
format
:
"%02d:%02d"
,
Int
(
current
)
/
60
,
Int
(
current
)
%
60
)
totalTimeLabel
.
text
=
String
(
format
:
"%02d:%02d"
,
Int
(
duration
)
/
60
,
Int
(
duration
)
%
60
)
if
let
currentIndex
=
currentIndex
,
currentIndex
!=
currentSegmentIndex
{
currentSegmentIndex
=
currentIndex
if
segmentCollection
.
numberOfSections
>
0
,
segmentCollection
.
numberOfItems
(
inSection
:
0
)
>
currentIndex
{
segmentCollection
.
scrollToItem
(
at
:
IndexPath
(
item
:
currentIndex
,
section
:
0
),
at
:
.
centeredHorizontally
,
animated
:
true
)
segmentCollection
.
reloadData
()
}
}
}
func
setPlaying
(
_
playing
:
Bool
)
{
isPlaying
=
playing
playButton
.
isSelected
=
playing
}
func
updateGiftCount
(
_
count
:
Int
)
{
guard
count
>
0
else
{
giftButton
.
isHidden
=
true
giftButton
.
setTitle
(
"0"
,
for
:
.
normal
)
return
}
giftButton
.
isHidden
=
false
if
count
>
99
{
giftButton
.
setTitle
(
"99+"
,
for
:
.
normal
)
}
else
{
giftButton
.
setTitle
(
"
\(
count
)
"
,
for
:
.
normal
)
}
}
// MARK: - Actions
@objc
private
func
playButtonTapped
()
{
isPlaying
.
toggle
()
playButton
.
isSelected
=
isPlaying
onPlayStatusChanged
?(
isPlaying
)
}
@objc
private
func
sliderValueChanged
()
{
let
time
=
TimeInterval
(
progressSlider
.
value
)
*
duration
onTimeChanged
?(
time
)
}
@objc
private
func
giftButtonTapped
()
{
giftButtonClickEvent
?()
}
}
// MARK: - UICollectionView DataSource & Delegate
extension
YHVideoProgressControl
:
UICollectionViewDataSource
,
UICollectionViewDelegate
,
UICollectionViewDelegateFlowLayout
{
func
collectionView
(
_
collectionView
:
UICollectionView
,
numberOfItemsInSection
section
:
Int
)
->
Int
{
return
segments
.
count
}
func
collectionView
(
_
collectionView
:
UICollectionView
,
cellForItemAt
indexPath
:
IndexPath
)
->
UICollectionViewCell
{
let
cell
=
collectionView
.
dequeueReusableCell
(
withReuseIdentifier
:
"SegmentCell"
,
for
:
indexPath
)
as!
SegmentCell
cell
.
configure
(
with
:
segments
[
indexPath
.
item
],
isSelected
:
indexPath
.
item
==
currentSegmentIndex
)
return
cell
}
func
collectionView
(
_
collectionView
:
UICollectionView
,
layout
collectionViewLayout
:
UICollectionViewLayout
,
sizeForItemAt
indexPath
:
IndexPath
)
->
CGSize
{
let
text
=
segments
[
indexPath
.
item
]
let
attr
=
NSAttributedString
(
string
:
text
,
attributes
:
[
.
font
:
UIFont
.
systemFont
(
ofSize
:
8
)])
let
width
=
attr
.
yh_width
(
containerHeight
:
20
)
+
8
return
CGSize
(
width
:
width
,
height
:
20
)
}
func
collectionView
(
_
collectionView
:
UICollectionView
,
didSelectItemAt
indexPath
:
IndexPath
)
{
currentSegmentIndex
=
indexPath
.
item
collectionView
.
scrollToItem
(
at
:
indexPath
,
at
:
.
centeredHorizontally
,
animated
:
true
)
collectionView
.
reloadData
()
onSegmentSelected
?(
indexPath
.
item
)
}
}
// MARK: - SegmentCell
class
SegmentCell
:
UICollectionViewCell
{
private
let
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
textColor
=
.
white
label
.
font
=
.
systemFont
(
ofSize
:
8
)
label
.
textAlignment
=
.
center
return
label
}()
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
setupUI
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
// override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// super.touchesBegan(touches, with: event)
// print("Cell touched")
// }
private
func
setupUI
()
{
backgroundColor
=
.
black
.
withAlphaComponent
(
0.3
)
layer
.
cornerRadius
=
2
contentView
.
addSubview
(
titleLabel
)
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
edges
.
equalToSuperview
()
}
}
func
configure
(
with
title
:
String
,
isSelected
:
Bool
)
{
titleLabel
.
text
=
title
titleLabel
.
textColor
=
isSelected
?
.
mainTextColor
:
.
white
backgroundColor
=
isSelected
?
.
white
:
.
black
.
withAlphaComponent
(
0.3
)
}
}
galaxy/galaxy/Classes/Modules/LivestreamSales(直播销售)/VM/YHLiveSalesViewModel.swift
View file @
1b6dc0bc
...
...
@@ -19,6 +19,8 @@ class YHLiveSalesViewModel: YHBaseViewModel {
// 获取环信Token信息
var
huanXinTokenModel
:
YHHuanXinTokenModel
?
// 快速生成订单
var
orderModel
:
YHLiveCreateOrderModel
?
}
extension
YHLiveSalesViewModel
{
...
...
@@ -175,30 +177,35 @@ extension YHLiveSalesViewModel {
callback
(
false
,
err
)
}
}
func
generateToken
(
channelName
:
String
,
uid
:
UInt
=
0
,
success
:
@escaping
(
String
?)
->
Void
)
{
guard
let
certificate
=
YhConstant
.
AgoraRtcKit
.
certificate
,
!
certificate
.
isEmpty
else
{
success
(
nil
)
return
}
let
params
=
[
"appCertificate"
:
certificate
,
"appId"
:
YhConstant
.
AgoraRtcKit
.
appId
,
"channelName"
:
channelName
,
"expire"
:
900
,
"src"
:
"iOS"
,
"ts"
:
""
.
timeStamp
,
"type"
:
1
,
"uid"
:
"
\(
uid
)
"
]
as
[
String
:
Any
]
let
strUrl
=
"https://toolbox.bj2.agoralab.co/v1/token/generate"
_
=
YHNetRequest
.
postRequest
(
url
:
strUrl
,
params
:
params
)
{
response
,
code
in
/*
注册环信用户 "source": 0, // 1直播 2 录播
"source_id": 0, // 直播或录播id
"product": {
"id": 0
}
*/
func
createOrder
(
source
:
Int
,
sourceId
:
Int
,
productId
:
Int
,
callBackBlock
:
@escaping
(
_
orderModel
:
YHLiveCreateOrderModel
?,
_
error
:
YHErrorModel
?)
->
Void
)
{
let
strUrl
=
YHBaseUrlManager
.
shared
.
curURL
()
+
YHAllApiName
.
LiveSales
.
createOrder
let
product
:
[
String
:
Int
]
=
[
"id"
:
productId
]
let
params
:
[
String
:
Any
]
=
[
"source"
:
source
,
"source_id"
:
sourceId
,
"product"
:
product
]
_
=
YHNetRequest
.
postRequest
(
url
:
strUrl
,
params
:
params
)
{
[
weak
self
]
json
,
_
in
// 1. json字符串 转 对象
if
let
dict
=
response
.
data
?
.
peel
as?
[
String
:
String
]
{
let
token
=
dict
[
"token"
]
success
(
token
)
if
json
.
code
==
200
{
guard
let
dic
=
json
.
data
?
.
peel
as?
[
String
:
Any
],
let
resultModel
=
YHLiveCreateOrderModel
.
deserialize
(
from
:
dic
)
else
{
let
err
=
YHErrorModel
(
errorCode
:
YHErrorCode
.
dictParseError
.
rawValue
,
errorMsg
:
YHErrorCode
.
dictParseError
.
description
())
callBackBlock
(
nil
,
err
)
return
}
self
?
.
orderModel
=
resultModel
callBackBlock
(
resultModel
,
nil
)
}
else
{
let
err
=
YHErrorModel
(
errorCode
:
Int32
(
json
.
code
),
errorMsg
:
json
.
msg
.
isEmpty
?
""
:
json
.
msg
)
callBackBlock
(
nil
,
err
)
}
success
(
nil
)
}
failBlock
:
{
err
in
success
(
nil
)
callBackBlock
(
nil
,
err
)
}
}
}
...
...
galaxy/galaxy/Classes/Tools/Helper/YhConstant.swift
View file @
1b6dc0bc
...
...
@@ -275,7 +275,6 @@ extension YhConstant {
struct
AgoraRtcKit
{
static
let
appId
:
String
=
"f1da9c5b9fb946148761278273f43a14"
static
let
certificate
:
String
?
=
"1776134c2dcb4d60bc3d1983fef02212"
}
// MARK: - 通知相关 名称
...
...
galaxy/galaxy/Classes/Tools/NetWork/YHAllApiName.swift
View file @
1b6dc0bc
...
...
@@ -680,6 +680,8 @@ class YHAllApiName {
static
let
leaveLiveRoom
=
"super-app/live/app-live-exit"
// 进入直播间--需求登录
static
let
joinLiveRoom
=
"super-app/live/app-live-join"
// 创建订单-立即购买
static
let
createOrder
=
"super-app/presale/app/order/create"
}
struct
AIChat
{
...
...
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_icon_pause.imageset/Contents.json
0 → 100644
View file @
1b6dc0bc
{
"images"
:
[
{
"idiom"
:
"universal"
,
"scale"
:
"1x"
},
{
"filename"
:
"live_icon_pause@2x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"2x"
},
{
"filename"
:
"live_icon_pause@3x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"3x"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_icon_pause.imageset/live_icon_pause@2x.png
0 → 100644
View file @
1b6dc0bc
182 Bytes
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_icon_pause.imageset/live_icon_pause@3x.png
0 → 100644
View file @
1b6dc0bc
211 Bytes
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_icon_play.imageset/Contents.json
0 → 100644
View file @
1b6dc0bc
{
"images"
:
[
{
"idiom"
:
"universal"
,
"scale"
:
"1x"
},
{
"filename"
:
"live_icon_play@2x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"2x"
},
{
"filename"
:
"live_icon_play@3x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"3x"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_icon_play.imageset/live_icon_play@2x.png
0 → 100644
View file @
1b6dc0bc
360 Bytes
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_icon_play.imageset/live_icon_play@3x.png
0 → 100644
View file @
1b6dc0bc
500 Bytes
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_msg_tips_icon.imageset/Contents.json
0 → 100644
View file @
1b6dc0bc
{
"images"
:
[
{
"idiom"
:
"universal"
,
"scale"
:
"1x"
},
{
"filename"
:
"live_msg_tips_icon@2x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"2x"
},
{
"filename"
:
"live_msg_tips_icon@3x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"3x"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_msg_tips_icon.imageset/live_msg_tips_icon@2x.png
0 → 100644
View file @
1b6dc0bc
1.7 KB
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_msg_tips_icon.imageset/live_msg_tips_icon@3x.png
0 → 100644
View file @
1b6dc0bc
2.33 KB
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_slider_thumb.imageset/Contents.json
0 → 100644
View file @
1b6dc0bc
{
"images"
:
[
{
"idiom"
:
"universal"
,
"scale"
:
"1x"
},
{
"filename"
:
"live_slider_thumb@2x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"2x"
},
{
"filename"
:
"live_slider_thumb@3x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"3x"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_slider_thumb.imageset/live_slider_thumb@2x.png
0 → 100644
View file @
1b6dc0bc
257 Bytes
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_slider_thumb.imageset/live_slider_thumb@3x.png
0 → 100644
View file @
1b6dc0bc
324 Bytes
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_time_separator.imageset/Contents.json
0 → 100644
View file @
1b6dc0bc
{
"images"
:
[
{
"idiom"
:
"universal"
,
"scale"
:
"1x"
},
{
"filename"
:
"live_time_separator@2x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"2x"
},
{
"filename"
:
"live_time_separator@3x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"3x"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_time_separator.imageset/live_time_separator@2x.png
0 → 100644
View file @
1b6dc0bc
220 Bytes
galaxy/galaxy/Res/Assets.xcassets/YinHeLive/live_time_separator.imageset/live_time_separator@3x.png
0 → 100644
View file @
1b6dc0bc
259 Bytes
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment