234 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			9.4 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) {
 | 
						|
                    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"
 | 
						|
            )
 | 
						|
        ]
 | 
						|
    )
 | 
						|
}
 |