2024-MacC-M14-Medio / SqoopDesignSystem / Sources / SQComponents / SQViews / ListCells / SQMusiclistCell.swift
SQMusiclistCell.swift
Raw
//
//  SQMusiclistCell.swift
//  Sqoop
//
//  Created by Greem on 10/11/24.
//

import SwiftUI
import SqoopDesignSystem

///    .

public struct SQMusiclistCell<T: Identifiable>: View {
#if os(iOS)
    @Environment(\.editMode) var editMode
#endif
    private var isPlaying: Bool
    let item: T
    var action: (()->())? = nil
    let playAction: (T?)->Void
    var imageURLString: String?
    var title: String
    var artist: String
    
    // duration viewModel 
    @State var playingDuration: Double = 0
    // endDuration = 60 viewmodel  
    
    
    @State var playTask: Task<(), any Error>?
    @State private var isBtnPressed = false
    private let endDuration: Double = 20
    
    public init(item: T,
                playingItemID: T.ID?,
                title: String,
                artist: String,
                imageURLString: String? = nil,
                action: (() -> Void)? = nil,
                playAction: @escaping (T?)->Void) {
        self.item = item
        self.isPlaying = item.id == playingItemID
        self.action = action
        self.imageURLString = imageURLString
        self.title = title
        self.artist = artist
        self.playAction = playAction
    }
    public var body: some View {
        HStack(spacing: 6) {
            ListCellAlbumArtView(imageURLString: imageURLString)
                .blur(radius: isPlaying ? 1 : 0)
                .overlay { if isPlaying { PlayingProgressOverlay(process: Double(playingDuration) / Double(endDuration)) } }
                .onTapGesture { withAnimation {
                    playAction(isPlaying ? nil : item)
                } }
                .onChange(of: isPlaying) { oldValue, newValue in
                    if newValue {
                        self.playTask = Task { @MainActor in
                            while playingDuration < endDuration {
                                try await Task.sleep(for: .seconds(0.01), tolerance: nil, clock: .continuous)
                                withAnimation { playingDuration += 0.01 }
                            }
                            playingDuration = 0
                            withAnimation { playAction(nil) }
                        }
                    } else {
                        self.playTask?.cancel()
                    }
                }
            Button {
                action?()
            } label: {
                HStack {
                    ListCellInformationLabel(isPlaying: isPlaying, title: title, artist: artist)
                    Spacer()
                }.contentShape(Rectangle())
            }.allowsHitTesting(action != nil)
        }
        .padding(.vertical, 10)
        .frame(height: 70)
        .listRowBackground(action == nil ? Color.clear : nil)
        .listRowInsets(.init(top: 0, leading: 16, bottom: 0, trailing: 16))
    }
}

struct ListCellInformationLabel: View {
    let isPlaying: Bool
    let title: String
    let artist: String
    var body: some View {
        VStack(alignment: .leading, spacing: 5) {
            HStack {
                if isPlaying {
                    Image(systemName: "waveform")
                        .font(.system(size: 14,weight: .regular))
                        .foregroundStyle(Color.textBrand)
                        .symbolEffect(.bounce, value: 100)
                }
                Text(title)
                    .fontWithLineHeight(.body01(weight: .medium))
                    .foregroundStyle(isPlaying ? Color.textBrand: Color.textPrimary)
            }
            Text(artist)
                .fontWithLineHeight(.body02(weight: .regular))
                .foregroundStyle(Color.textSecondary)
        }
        .multilineTextAlignment(.leading)
    }
}

//    
struct ListCellAlbumArtView: View {
    let imageURLString: String?
    var body: some View {
        Group {
            if let imageURL = URL(string: imageURLString ?? "") {
                AsyncImage(url: imageURL) { phase in
                    switch phase {
                    case .empty:
                        ProgressView()
                    case .success(let image):
                        image
                            .resizable()
                            .scaledToFit()
                    case .failure:
                        Image("EmptyMusic")
                            .resizable()
                            .scaledToFit()
                    @unknown default:
                        Image("EmptyMusic")
                            .resizable()
                            .scaledToFit()
                    }
                }
            } else {
                Image("EmptyMusic")
                    .resizable()
                    .scaledToFill()
            }
        }.frame(width: 50, height: 50)
            .clipShape(RoundedRectangle(cornerRadius: 2))
    }
}
// MARK: --   
struct PlayingProgressOverlay: View {
    let process: Double
    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 2)
                .fill(.clear)
                .background(Material.ultraThickMaterial.opacity(0.66))
            
            Circle().trim(from: 0.0, to: process)
                .stroke(Color.textBrand,style: StrokeStyle(lineWidth: 3, lineCap: .round))
                .padding(.all, 6.7).rotationEffect(.degrees(-90), anchor: .center)
            
            Image(systemName: "pause.fill")
                .font(.system(size: 20,weight: .light))
                .foregroundStyle(Color.textBrand)
        }
    }
}

#Preview {
    ZStack {
        Color.black.ignoresSafeArea(.all)
        //        ListContentView()
    }.loadSqoopFontSystem()
}





//public struct SQMusiclistCell<T: Identifiable>: View {

//    @Environment(\.editMode) var editMode

//    private var isPlaying: Bool
//    let item: T
//    var action: (()->())? = nil
//    let playAction: (T) async throws -> Void
//    var imageURLString: String? = nil
//    var title: String
//    var artist: String
//    
//    @State var playingDuration: Double = 0
//    @State var playTask: Task<(), any Error>?
//    @State private var isBtnPressed = false
//    private let endDuration: Double = 20
//    
//    public init(item: T,
//                playingItemID: T.ID?,
//                title: String,
//                artist: String,
//                imageURLString: String? = nil,
//                action: (() -> Void)? = nil,
//                playAction: @escaping (T) async throws -> Void) {
//        self.item = item
//        self.isPlaying = item.id == playingItemID
//        self.action = action
//        self.imageURLString = imageURLString
//        self.title = title
//        self.artist = artist
//        self.playAction = playAction
//    }