219 lines
8.8 KiB
Swift
219 lines
8.8 KiB
Swift
//
|
|
// ContentPlayerView.swift
|
|
// SodaLive
|
|
//
|
|
// Created by klaus on 12/16/24.
|
|
//
|
|
|
|
import SwiftUI
|
|
import Kingfisher
|
|
import Sliders
|
|
|
|
struct ContentPlayerView: View {
|
|
|
|
@StateObject var playerManager = ContentPlayerPlayManager.shared
|
|
|
|
@Binding var isShowing: Bool
|
|
let playlist: [AudioContentPlaylistContent]
|
|
|
|
var body: some View {
|
|
BaseView(isLoading: $playerManager.isLoading) {
|
|
VStack(spacing: 0) {
|
|
HStack(spacing: 0) {
|
|
Spacer()
|
|
|
|
Image("ic_bottom_white")
|
|
.onTapGesture { isShowing = false }
|
|
}
|
|
|
|
if !playerManager.isShowPlaylist {
|
|
Text(playerManager.title)
|
|
.font(.custom(Font.medium.rawValue, size: 16))
|
|
.foregroundColor(.grayee)
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.padding(.top, 16)
|
|
|
|
HStack(spacing: 5.3) {
|
|
KFImage(URL(string: playerManager.creatorProfileUrl))
|
|
.cancelOnDisappear(true)
|
|
.downsampling(size: CGSize(width: 26.7, height: 26.7))
|
|
.resizable()
|
|
.scaledToFill()
|
|
.frame(width: 26.7, height: 26.7)
|
|
.clipShape(Circle())
|
|
|
|
Text(playerManager.nickname)
|
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
|
.foregroundColor(.gray90)
|
|
|
|
Spacer()
|
|
}
|
|
.padding(.top, 21)
|
|
}
|
|
|
|
Spacer(minLength: 13.3)
|
|
|
|
if playerManager.isShowPlaylist {
|
|
ScrollView(.vertical) {
|
|
LazyVStack(alignment: .leading, spacing: 0) {
|
|
ForEach(0..<playerManager.playlist.count, id: \.self) {
|
|
let item = playerManager.playlist[$0]
|
|
PlaylistContentItemView(item: item)
|
|
.padding(13.3)
|
|
.frame(maxWidth: .infinity)
|
|
.background(
|
|
Color.button
|
|
.opacity(
|
|
item.id == playerManager.id ? 0.2 : 0
|
|
)
|
|
)
|
|
.cornerRadius(6.7)
|
|
.onTapGesture {
|
|
playerManager.playSelectedContent(contentId: item.id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
KFImage(URL(string: playerManager.coverImageUrl))
|
|
.cancelOnDisappear(true)
|
|
.downsampling(size: CGSize(width: 240, height: 240))
|
|
.resizable()
|
|
.scaledToFill()
|
|
.frame(width: 240, height: 240)
|
|
.cornerRadius(8)
|
|
}
|
|
|
|
Spacer()
|
|
|
|
if playerManager.duration > 0 {
|
|
ValueSlider(
|
|
value: $playerManager.currentTime,
|
|
in: 0...playerManager.duration,
|
|
step: 1.0,
|
|
onEditingChanged: { editing in
|
|
playerManager.isEditing = editing
|
|
if !editing {
|
|
playerManager.seek(to: playerManager.currentTime)
|
|
}
|
|
}
|
|
)
|
|
.valueSliderStyle(
|
|
HorizontalValueSliderStyle(
|
|
track: HorizontalValueTrack(
|
|
view: Rectangle().foregroundColor(Color.button),
|
|
mask: Rectangle()
|
|
)
|
|
.background(Rectangle().foregroundColor(Color.gray97.opacity(0.3)))
|
|
.frame(height: 5.3),
|
|
thumbSize: CGSize(width: 10, height: 10),
|
|
options: .interactiveTrack
|
|
)
|
|
)
|
|
.frame(height: 11)
|
|
}
|
|
|
|
HStack(spacing: 0) {
|
|
Text(secondsToMinutesSeconds(seconds: Int(playerManager.currentTime)))
|
|
.font(.custom(Font.medium.rawValue, size: 12))
|
|
.foregroundColor(.graybb)
|
|
|
|
Spacer()
|
|
|
|
Text(secondsToMinutesSeconds(seconds: Int(playerManager.duration)))
|
|
.font(.custom(Font.medium.rawValue, size: 12))
|
|
.foregroundColor(.gray77)
|
|
}
|
|
.padding(.top, 5.3)
|
|
|
|
HStack(spacing: 0) {
|
|
Image("ic_skip_back")
|
|
.onTapGesture {
|
|
playerManager.playPreviousContent()
|
|
}
|
|
|
|
Spacer()
|
|
|
|
Image("ic_player_prev_10")
|
|
.onTapGesture {
|
|
playerManager.seekBackward(seconds: 10)
|
|
}
|
|
|
|
Spacer()
|
|
|
|
Image(playerManager.isPlaying ? "ic_player_pause" : "ic_player_play")
|
|
.onTapGesture {
|
|
playerManager.playOrPause()
|
|
}
|
|
|
|
Spacer()
|
|
|
|
Image("ic_player_next_10")
|
|
.onTapGesture {
|
|
playerManager.seekForward(seconds: 10)
|
|
}
|
|
|
|
Spacer()
|
|
|
|
Image("ic_skip_forward")
|
|
.onTapGesture {
|
|
playerManager.playNextContent()
|
|
}
|
|
}
|
|
.padding(.vertical, 21)
|
|
|
|
HStack(spacing: 0) {
|
|
Spacer()
|
|
|
|
Image("ic_playlist")
|
|
.padding(5)
|
|
.background(Color.gray33.opacity(playerManager.isShowPlaylist ? 1 : 0))
|
|
.cornerRadius(playerManager.isShowPlaylist ? 6.7 : 0)
|
|
.onTapGesture { playerManager.isShowPlaylist.toggle() }
|
|
}
|
|
}
|
|
.padding(20)
|
|
.onAppear {
|
|
if !playlist.isEmpty {
|
|
playerManager.setPlaylist(playlist: playlist)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func secondsToMinutesSeconds(seconds: Int) -> String {
|
|
let hours = String(format: "%02d", seconds / 3600)
|
|
let minute = String(format: "%02d", (seconds % 3600) / 60)
|
|
let second = String(format: "%02d", seconds % 60)
|
|
|
|
return "\(hours):\(minute):\(second)"
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
ContentPlayerView(
|
|
isShowing: .constant(true),
|
|
playlist: [
|
|
AudioContentPlaylistContent(
|
|
id: 1,
|
|
title: "안녕하세요 오늘은 커버곡을 들려드리려고 해요",
|
|
category: "커버곡",
|
|
coverUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
|
duration: "00:30:20",
|
|
creatorNickname: "유저1",
|
|
creatorProfileUrl: "https://test-cf.sodalive.net/profile/default-profile.png"
|
|
),
|
|
|
|
AudioContentPlaylistContent(
|
|
id: 2,
|
|
title: "안녕하세요 오늘은 커버곡을 들려드리려고 해요안녕하세요 오늘은 커버곡을 들려드리려고 해요안녕하세요 오늘은 커버곡을 들려드리려고 해요안녕하세요 오늘은 커버곡을 들려드리려고 해요안녕하세요 오늘은 커버곡을 들려드리려고 해요안녕하세요 오늘은 커버곡을 들려드리려고 해요",
|
|
category: "커버곡",
|
|
coverUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
|
duration: "00:30:20",
|
|
creatorNickname: "유저1",
|
|
creatorProfileUrl: "https://test-cf.sodalive.net/profile/default-profile.png"
|
|
)
|
|
]
|
|
)
|
|
}
|