/ flo / SongView.swift
SongView.swift
  1  //
  2  //  SongView.swift
  3  //  flo
  4  //
  5  //  Created by rizaldy on 26/06/24.
  6  //
  7  
  8  import SwiftUI
  9  
 10  struct SongView: View {
 11    @Environment(\.dismiss) private var dismiss
 12    @EnvironmentObject var downloadViewModel: DownloadViewModel
 13  
 14    @ObservedObject var viewModel: AlbumViewModel
 15    var playerViewModel: PlayerViewModel
 16    var isDownloadScreen: Bool = false
 17  
 18    var body: some View {
 19      VStack {
 20        ForEach(Array(viewModel.album.songs.enumerated()), id: \.element) { idx, song in
 21          VStack {
 22            HStack(alignment: .top) {
 23              Text("\(song.trackNumber.description)")
 24                .customFont(.caption1)
 25                .foregroundColor(.gray)
 26                .padding(.trailing, 5)
 27  
 28              VStack(alignment: .leading) {
 29                Text(song.title)
 30                  .fontWeight(.medium)
 31  
 32                if song.id.hasPrefix("pl:") {
 33                  Text(song.artist).customFont(.caption1).offset(y: 5)
 34                } else {
 35                  if viewModel.album.albumArtist != viewModel.album.artist {
 36                    Text(song.artist).customFont(.caption1).offset(y: 5)
 37                  }
 38                }
 39  
 40                Spacer()
 41              }
 42  
 43              Spacer()
 44  
 45              if !song.fileUrl.isEmpty {
 46                Image(systemName: "arrow.down.circle.fill")
 47                  .font(.system(size: 14))
 48              }
 49  
 50              Text(timeString(for: song.duration)).customFont(.caption1)
 51            }
 52          }
 53          .padding()
 54          .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
 55          .listRowSeparator(.hidden)
 56          .contentShape(Rectangle())
 57          .onTapGesture {
 58            playerViewModel.playBySong(
 59              idx: idx, item: viewModel.album, isFromLocal: viewModel.isDownloaded)
 60          }
 61          .contextMenu {
 62            VStack {
 63              if !song.fileUrl.isEmpty {
 64                Button(role: .destructive) {
 65                  viewModel.removeDownloadSong(album: viewModel.album, songId: song.id)
 66                  viewModel.setActiveAlbum(album: viewModel.album)
 67                  if isDownloadScreen {
 68                    dismiss()
 69                    viewModel.fetchDownloadedAlbums()
 70                  }
 71                } label: {
 72                  HStack {
 73                    Text("Remove Download")
 74                    Image(systemName: "arrow.down.circle")
 75                  }
 76                }
 77              } else {
 78                Button {
 79                  viewModel.downloadAlbum(viewModel.album)
 80                  downloadViewModel.addIndividualItem(
 81                    album: viewModel.album, song: viewModel.album.songs[idx])
 82                } label: {
 83                  HStack {
 84                    Text("Download")
 85                    Image(systemName: "arrow.down.circle")
 86                  }
 87                }
 88              }
 89            }
 90          }
 91        }
 92        .listStyle(PlainListStyle()).customFont(.body)
 93      }
 94    }
 95  }
 96  
 97  struct SongView_Previews: PreviewProvider {
 98    static let songs: [Song] = [
 99      Song(
100        id: "0", title: "Song 1", albumId: "", albumName: "Album name", artist: "Artist Name",
101        trackNumber: 1, discNumber: 0, bitRate: 0,
102        sampleRate: 44100,
103        suffix: "mp4a", duration: 200, mediaFileId: "0"),
104      Song(
105        id: "1", title: "Song 2", albumId: "", albumName: "Album name", artist: "Artist Name",
106        trackNumber: 2, discNumber: 0, bitRate: 0,
107        sampleRate: 44100,
108        suffix: "mp4a", duration: 200, mediaFileId: "1"),
109      Song(
110        id: "2", title: "Song 3", albumId: "", albumName: "Album name", artist: "Artist Name",
111        trackNumber: 3, discNumber: 0, bitRate: 0,
112        sampleRate: 44100,
113        suffix: "mp4a", duration: 200, mediaFileId: "2"),
114      Song(
115        id: "3", title: "Song 4", albumId: "", albumName: "Album name", artist: "Artist Name",
116        trackNumber: 4, discNumber: 0, bitRate: 0,
117        sampleRate: 44100,
118        suffix: "mp4a", duration: 200, mediaFileId: "3"),
119      Song(
120        id: "4", title: "Song 5", albumId: "", albumName: "Album name", artist: "Artist Name",
121        trackNumber: 5, discNumber: 0, bitRate: 0,
122        sampleRate: 44100,
123        suffix: "mp4a", duration: 200, mediaFileId: "4"),
124      Song(
125        id: "5", title: "Song 6", albumId: "", albumName: "Album name", artist: "Artist Name",
126        trackNumber: 6, discNumber: 0, bitRate: 0,
127        sampleRate: 44100,
128        suffix: "mp4a", duration: 200, mediaFileId: "5"),
129      Song(
130        id: "6", title: "Song 7", albumId: "", albumName: "Album name", artist: "Artist Name",
131        trackNumber: 7, discNumber: 0, bitRate: 0,
132        sampleRate: 44100,
133        suffix: "mp4a", duration: 200, mediaFileId: "6"),
134      Song(
135        id: "7", title: "Song 8", albumId: "", albumName: "Album name", artist: "Artist Name",
136        trackNumber: 8, discNumber: 0, bitRate: 0,
137        sampleRate: 44100,
138        suffix: "mp4a", duration: 200, mediaFileId: "7"),
139    ]
140  
141    static let album: Album = Album(
142      name: "Album name", artist: "Artist name", songs: songs)
143  
144    @StateObject static var viewModel: AlbumViewModel = AlbumViewModel(album: album)
145    @StateObject static var playerViewModel: PlayerViewModel = PlayerViewModel()
146  
147    static var previews: some View {
148      SongView(viewModel: viewModel, playerViewModel: playerViewModel)
149    }
150  }