콘텐츠 추가
This commit is contained in:
171
SodaLive/Sources/Content/Detail/ContentDetailPlayView.swift
Normal file
171
SodaLive/Sources/Content/Detail/ContentDetailPlayView.swift
Normal file
@@ -0,0 +1,171 @@
|
||||
//
|
||||
// ContentDetailPlayView.swift
|
||||
// SodaLive
|
||||
//
|
||||
// Created by klaus on 2023/08/13.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Kingfisher
|
||||
import Sliders
|
||||
|
||||
struct ContentDetailPlayView: View {
|
||||
|
||||
let audioContent: GetAudioContentDetailResponse
|
||||
@Binding var isShowPreviewAlert: Bool
|
||||
|
||||
@StateObject var contentPlayManager = ContentPlayManager.shared
|
||||
|
||||
@State private var isRepeat = UserDefaults.bool(forKey: .isContentPlayLoop)
|
||||
@State private var isEditing = false
|
||||
@State private var progress: TimeInterval = 0
|
||||
@State private var timer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect()
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
ZStack {
|
||||
KFImage(URL(string: audioContent.coverImageUrl))
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.frame(
|
||||
width: screenSize().width - 26.7,
|
||||
height: screenSize().width - 26.7,
|
||||
alignment: .center
|
||||
)
|
||||
.cornerRadius(10.7, corners: [.topLeft, .topRight])
|
||||
|
||||
Image(isPlaying() ? "btn_audio_content_pause" : "btn_audio_content_play")
|
||||
.onTapGesture {
|
||||
if isPlaying() {
|
||||
contentPlayManager.pauseAudio()
|
||||
} else {
|
||||
contentPlayManager.startTimer = startTimer
|
||||
contentPlayManager.stopTimer = stopTimer
|
||||
|
||||
contentPlayManager.playAudio(
|
||||
contentId: audioContent.contentId,
|
||||
title: audioContent.title,
|
||||
nickname: audioContent.creator.nickname,
|
||||
coverImage: audioContent.coverImageUrl,
|
||||
contentUrl: audioContent.contentUrl,
|
||||
isFree: audioContent.price <= 0,
|
||||
isPreview: !audioContent.existOrdered && audioContent.price > 0
|
||||
)
|
||||
isShowPreviewAlert = true
|
||||
}
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 13.3) {
|
||||
Spacer()
|
||||
|
||||
ValueSlider(
|
||||
value: audioContent.contentId == contentPlayManager.contentId ? $progress : .constant(0),
|
||||
in: sliderRange(),
|
||||
onEditingChanged: { editing in
|
||||
isEditing = editing
|
||||
if !editing {
|
||||
contentPlayManager.setCurrentTime(progress)
|
||||
}
|
||||
}
|
||||
)
|
||||
.valueSliderStyle(
|
||||
HorizontalValueSliderStyle(
|
||||
track: HorizontalValueTrack(
|
||||
view: Rectangle().foregroundColor(Color(hex: "9970ff")),
|
||||
mask: Rectangle()
|
||||
)
|
||||
.background(Rectangle().foregroundColor(Color(hex: "979797").opacity(0.3)))
|
||||
.frame(height: 5.3),
|
||||
thumbSize: CGSizeZero,
|
||||
options: .interactiveTrack
|
||||
)
|
||||
)
|
||||
.frame(height: 5.3)
|
||||
}
|
||||
|
||||
if contentPlayManager.isLoading {
|
||||
LoadingView()
|
||||
}
|
||||
}
|
||||
.frame(
|
||||
width: screenSize().width - 26.7,
|
||||
height: screenSize().width - 26.7
|
||||
)
|
||||
|
||||
HStack(spacing: 0) {
|
||||
Text("\(getProgress()) / \(getDuration())")
|
||||
.font(.custom(Font.medium.rawValue, size: 14.7))
|
||||
.foregroundColor(.white)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image(
|
||||
isRepeat ?
|
||||
"btn_player_repeat" :
|
||||
"btn_player_repeat_done"
|
||||
)
|
||||
.onTapGesture {
|
||||
isRepeat = !UserDefaults.bool(forKey: .isContentPlayLoop)
|
||||
UserDefaults.set(
|
||||
isRepeat,
|
||||
forKey: .isContentPlayLoop
|
||||
)
|
||||
}
|
||||
}
|
||||
.frame(width: screenSize().width - 40)
|
||||
}
|
||||
.onAppear {
|
||||
if !isPlaying() {
|
||||
stopTimer()
|
||||
}
|
||||
}
|
||||
.onReceive(timer) { _ in
|
||||
guard let player = contentPlayManager.player, !isEditing else { return }
|
||||
self.progress = player.currentTime
|
||||
}
|
||||
}
|
||||
|
||||
private func isPlaying() -> Bool {
|
||||
return contentPlayManager.contentId == audioContent.contentId && contentPlayManager.isPlaying
|
||||
}
|
||||
|
||||
private func sliderRange() -> ClosedRange<Double> {
|
||||
if audioContent.contentId == contentPlayManager.contentId {
|
||||
return 0...contentPlayManager.duration
|
||||
} else {
|
||||
return 0...0
|
||||
}
|
||||
}
|
||||
|
||||
private func getProgress() -> String {
|
||||
if audioContent.contentId == contentPlayManager.contentId {
|
||||
return secondsToMinutesSeconds(seconds: Int(progress))
|
||||
} else {
|
||||
return secondsToMinutesSeconds(seconds: 0)
|
||||
}
|
||||
}
|
||||
|
||||
private func getDuration() -> String {
|
||||
if audioContent.contentId == contentPlayManager.contentId {
|
||||
return secondsToMinutesSeconds(seconds: Int(contentPlayManager.duration))
|
||||
} else {
|
||||
return audioContent.duration
|
||||
}
|
||||
}
|
||||
|
||||
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)"
|
||||
}
|
||||
|
||||
private func startTimer() {
|
||||
timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()
|
||||
}
|
||||
|
||||
private func stopTimer() {
|
||||
timer.upstream.connect().cancel()
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user