// // 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.. 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) { Image({ switch playerManager.loopState { case .waitingForEnd: "ic_loop_segment_start_set" case .looping: "ic_loop_segment_active" default: "ic_loop_segment_idle" } }()) .padding(5) .onTapGesture { playerManager.toggleLoop() } 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" ) ] ) }