// // AuditionApplicantRecordingView.swift // SodaLive // // Created by klaus on 1/7/25. // import SwiftUI struct AuditionApplicantRecordingView: View { @StateObject var soundManager = CreatorCommunitySoundManager() @Binding var isShowing: Bool @Binding var isShowPopup: Bool @Binding var errorMessage: String let onClickCompleteRecording: (String, Data) -> Void @State private var tempFileName = "" var body: some View { ZStack { Color.black.opacity(0.7) .ignoresSafeArea() GeometryReader { proxy in VStack { Spacer() VStack { VStack(spacing: 0) { HStack(spacing: 0) { Text("오디션 녹음") .font(.custom(Font.bold.rawValue, size: 18.3)) .foregroundColor(.white) Spacer() Image("ic_close_white") .resizable() .frame(width: 20, height: 20) .onTapGesture { isShowing = false } } .padding(.horizontal, 26.7) .padding(.top, 26.7) } Text(soundManager.timeString) .font(.custom(Font.bold.rawValue, size: 33.3)) .foregroundColor(.white) .padding(.top, 80) switch soundManager.recordMode { case .RECORD: if !soundManager.isLoading { Image(soundManager.isRecording ? "ic_record_stop" : "ic_record") .resizable() .frame(width: 70, height: 70) .padding(.vertical, 52.3) .onTapGesture { if !soundManager.isLoading { if !soundManager.isRecording { tempFileName = "voiceon_now_voice_\(Int(Date().timeIntervalSince1970 * 1000)).m4a" soundManager.startRecording(tempFileName) } else { soundManager.stopRecording() soundManager.recordMode = .PLAY } } } } case .PLAY: if !soundManager.isLoading { VStack(spacing: 0) { HStack(spacing: 0) { Spacer() Text("삭제") .font(.custom(Font.medium.rawValue, size: 15.3)) .foregroundColor(Color.graybb.opacity(0)) Spacer() Image( !soundManager.isPlaying ? "ic_record_play" : "ic_record_pause" ) .onTapGesture { if !soundManager.isLoading { if !soundManager.isPlaying { soundManager.playAudio() } else { soundManager.stopAudio() } } } Spacer() Text("삭제") .font(.custom(Font.medium.rawValue, size: 15.3)) .foregroundColor(Color.graybb) .onTapGesture { soundManager.stopAudio() soundManager.deleteAudioFile() soundManager.recordMode = .RECORD } Spacer() } .padding(.vertical, 52.3) HStack(spacing: 13.3) { Text("다시 녹음") .font(.custom(Font.bold.rawValue, size: 18.3)) .foregroundColor(Color.button) .frame(width: (proxy.size.width - 40) / 3, height: 50) .background(Color.button.opacity(0.2)) .cornerRadius(10) .overlay( RoundedRectangle(cornerRadius: 10) .stroke(Color.button, lineWidth: 1.3) ) .onTapGesture { soundManager.stopAudio() soundManager.deleteAudioFile() soundManager.recordMode = .RECORD } Text("녹음완료") .font(.custom(Font.bold.rawValue, size: 18.3)) .foregroundColor(.white) .frame(width: (proxy.size.width - 40) * 2 / 3, height: 50) .background(Color.button) .cornerRadius(10) .onTapGesture { do { let soundData = try Data(contentsOf: soundManager.getAudioFileURL()) onClickCompleteRecording(tempFileName, soundData) } catch { errorMessage = "녹음파일을 생성하지 못했습니다.\n다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." isShowPopup = true } } } .padding(.bottom, 40) .padding(.horizontal, 13.3) } } } if proxy.safeAreaInsets.bottom > 0 { Rectangle() .foregroundColor(Color.gray22) .frame(width: proxy.size.width, height: 15.3) } if soundManager.isLoading { LoadingView() } } .background(Color(hex: "222222")) .cornerRadius(16.7, corners: [.topLeft, .topRight]) } .edgesIgnoringSafeArea(.bottom) .onAppear { soundManager.prepareRecording() } } } .popup(isPresented: $soundManager.isShowPopup, type: .toast, position: .top, autohideIn: 2) { GeometryReader { geo in HStack { Spacer() Text(soundManager.errorMessage) .padding(.vertical, 13.3) .padding(.horizontal, 6.7) .frame(width: screenSize().width - 66.7, alignment: .center) .font(.custom(Font.medium.rawValue, size: 12)) .background(Color.button) .foregroundColor(Color.white) .multilineTextAlignment(.center) .cornerRadius(20) .padding(.top, 66.7) Spacer() } .onDisappear { if soundManager.onClose { isShowing = false } } } } } } #Preview { AuditionApplicantRecordingView( isShowing: .constant(false), isShowPopup: .constant(false), errorMessage: .constant(""), onClickCompleteRecording: { _, _ in } ) }