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 }