// // VoiceMessageItemView.swift // SodaLive // // Created by klaus on 2023/08/10. // import SwiftUI import Kingfisher struct VoiceMessageItemView: View { let index: Int let item: VoiceMessageItem let currentFilter: MessageFilterTab let soundManager: SoundManager @Binding var openPlayerItemIndex: Int let onClickSave: () -> Void let onClickReply: () -> Void let onClickDelete: () -> Void @State var progress: TimeInterval = 0 @State var timer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect() var body: some View { let nickname = item.recipientNickname == UserDefaults.string(forKey: .nickname) ? item.senderNickname : item.recipientNickname let profileUrl = item.recipientNickname == UserDefaults.string(forKey: .nickname) ? item.senderProfileImageUrl : item.recipientProfileImageUrl VStack(spacing: 10) { HStack(spacing: 0) { KFImage(URL(string: profileUrl)) .resizable() .scaledToFill() .frame(width: 46.7, height: 46.7, alignment: .top) .clipped() .cornerRadius(23.4) Text(nickname) .font(.custom(Font.medium.rawValue, size: 13.3)) .foregroundColor(Color(hex: "eeeeee")) .padding(.leading, 13.3) Spacer() Text(item.date) .font(.custom(Font.light.rawValue, size: 12)) .foregroundColor(Color(hex: "525252")) } .contentShape(Rectangle()) .onTapGesture { openPlayerItemIndex = openPlayerItemIndex == index ? -1 : index } if openPlayerItemIndex == index { VStack(spacing: 0) { ProgressView(value: progress, total: soundManager.duration) .progressViewStyle(LinearProgressViewStyle(tint: Color(hex: "9970ff"))) .padding(.horizontal, 13.3) HStack(spacing: 0) { Text("00:00") .font(.custom(Font.medium.rawValue, size: 10.7)) .foregroundColor(Color(hex: "bbbbbb")) Spacer() Text("\(secondsToMinutesSeconds(seconds: Int(soundManager.duration)))") .font(.custom(Font.medium.rawValue, size: 10.7)) .foregroundColor(Color(hex: "bbbbbb")) } .padding(.horizontal, 13.3) .padding(.top, 6.7) HStack(spacing: 0) { Image("ic_save") .resizable() .frame( width: currentFilter == .receive ? 27 : 22, height: currentFilter == .receive ? 27 : 22 ) .opacity(currentFilter == .receive ? 1 : 0) .onTapGesture { if currentFilter == .receive { onClickSave() } } Spacer() Image(soundManager.isPlaying ? "btn_bar_stop": "btn_bar_play") .resizable() .frame(width: 40, height: 40) .onTapGesture { if soundManager.isPlaying { soundManager.stopAudio() } else { soundManager.playAudio() } } Spacer() if currentFilter == .receive { Image("ic_mic_paint") .resizable() .frame(width: 27, height: 27) .onTapGesture { onClickReply() } } if currentFilter == .sent || currentFilter == .keep { Image(systemName: "trash.fill") .resizable() .frame(width: 22, height: 22) .onTapGesture { onClickDelete() } } } .padding(.top, 24.3) .padding(.horizontal, 13.3) } .padding(.vertical, 20) .background(Color(hex: "9970ff").opacity(0.2)) .cornerRadius(6.7) .onAppear { soundManager.startTimer = startTimer soundManager.stopTimer = stopTimer soundManager.prepareForPlay(URL(string: item.voiceMessageUrl)!) } .onDisappear { soundManager.stopAudio() } } } .frame(width: screenSize().width - 26.7) .background(Color.black) .onAppear { stopTimer() } .onReceive(timer) { _ in self.progress = soundManager.getPlayerCurrentTime() } } private func secondsToMinutesSeconds(seconds: Int) -> String { let minute = String(format: "%02d", seconds / 60) let second = String(format: "%02d", seconds % 60) return "\(minute):\(second)" } private func startTimer() { timer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect() } private func stopTimer() { timer.upstream.connect().cancel() } } struct VoiceMessageItemView_Previews: PreviewProvider { static var previews: some View { VoiceMessageItemView( index: 0, item: VoiceMessageItem( messageId: 24, senderId: 13, senderNickname: "user5", senderProfileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png", recipientNickname: "user8", recipientProfileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png", voiceMessageUrl: "", date: "2022-07-02 01:42:43", isKept: false ), currentFilter: .keep, soundManager: SoundManager(), openPlayerItemIndex: .constant(0), onClickSave: {}, onClickReply: {}, onClickDelete: {} ) } }