Skip to content

Commit

Permalink
add initial (very buggy) queue viewer
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMoonThatRises committed Dec 16, 2024
1 parent e31ad19 commit b2a9e16
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 44 deletions.
6 changes: 6 additions & 0 deletions Spwifiy/Localizations/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,18 @@
},
"My Library" : {
"extractionState" : "manual"
},
"Next up:" : {

},
"Pin to Home" : {

},
"Pins" : {

},
"Play some songs to populate the queue" : {

},
"Playlists" : {

Expand Down
116 changes: 116 additions & 0 deletions Spwifiy/Views/MainElements/QueueElementView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//
// QueueElementView.swift
// Spwifiy
//
// Created by Peter Duanmu on 12/12/24.
//

import SwiftUI
import SpotifyWebAPI

struct QueueElementView: View {

enum CurrentView: String, CaseIterable {
case queueView = "Queue"
case previousView = "Recent"
}

@ObservedObject var avAudioPlayer: AVAudioPlayer

@Binding var selectedArtist: Artist?

@State var currentView: CurrentView = .queueView

var body: some View {
VStack(alignment: .leading) {
UnderlinedViewMenu(types: CurrentView.allCases,
currentOption: $currentView)

if avAudioPlayer.trackQueue.count > 0 {
TrackQueueView(track: avAudioPlayer.trackQueue[avAudioPlayer.playingIndex],
selectedArtist: $selectedArtist)

Spacer()
.frame(height: 40)

Text("Next up:")
.foregroundStyle(.fgPrimary)
.font(.satoshiBlack(16))

Spacer()
.frame(height: 20)

List {
ForEach(currentView == .queueView
? avAudioPlayer.trackQueue
.suffix(avAudioPlayer.trackQueue.count - avAudioPlayer.playingIndex - 1)
: avAudioPlayer.previousQueue,
id: \.uri) { track in
TrackQueueView(track: track,
selectedArtist: $selectedArtist)
}
.onMove { indices, newOffset in
avAudioPlayer.trackQueue.move(fromOffsets: indices,
toOffset: newOffset)
}
}
} else {
Text("Play some songs to populate the queue")
.padding()
}

Spacer()
}
.padding()
.frame(width: 300)
.foregroundStyle(.fgSecondary)
}

}

struct TrackQueueView: View {

let track: Track

@Binding var selectedArtist: Artist?

var body: some View {
HStack {
CroppedCachedAsyncImage(url: track.album?.images?.first?.url,
width: 50,
height: 50,
alignment: .center,
clipShape: RoundedRectangle(cornerRadius: 5))

VStack(alignment: .leading) {
Text(track.name)
.foregroundStyle(.fgPrimary)
.font(.satoshiCustom(nil, 14))

Button {
selectedArtist = track.artists?.first
} label: {
Text(track.artists?.description ?? "Artist")
}
.buttonStyle(.plain)
.cursorHover(.pointingHand)
}
.lineLimit(1)
.frame(maxWidth: 150)
.fixedSize()

Spacer()

Button {

} label: {
Image("spwifiy.close")
.resizable()
.frame(width: 40, height: 40)
}
.buttonStyle(.plain)
.cursorHover(.pointingHand)
}
}

}
102 changes: 58 additions & 44 deletions Spwifiy/Views/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,58 +47,72 @@ struct MainView: View {

Spacer()

Group {
switch mainViewModel.currentViewAnimated {
// default view
case .home:
HomeView(spotifyDataViewModel: spotifyDataViewModel,
mainViewModel: mainViewModel)

// sidebar views
case .likedSongs:
LikedSongsView(spotifyCache: spotifyCache,
selectedArtist: $mainViewModel.selectedArtist,
selectedAlbum: $mainViewModel.selectedAlbum)

// layers deep abstracted view
case .selectedPlaylist:
if let selectedPlaylist = mainViewModel.selectedPlaylist {
SelectedPlaylistView(
showFlags: PlaylistShowFlags.none,
spotifyCache: spotifyCache,
avAudioPlayer: avAudioPlayer,
playlist: selectedPlaylist,
selectedArtist: $mainViewModel.selectedArtist,
selectedAlbum: $mainViewModel.selectedAlbum
)
} else {
Text("Unable to get selected playlist")
.font(.title)
}
case .selectedArtist:
if let artist = mainViewModel.selectedArtist {
ArtistView(spotifyCache: spotifyCache, artist: artist)
} else {
Text("Unable to get selected artist")
HStack {
Group {
switch mainViewModel.currentViewAnimated {
// default view
case .home:
HomeView(spotifyDataViewModel: spotifyDataViewModel,
mainViewModel: mainViewModel)

// sidebar views
case .likedSongs:
LikedSongsView(spotifyCache: spotifyCache,
selectedArtist: $mainViewModel.selectedArtist,
selectedAlbum: $mainViewModel.selectedAlbum)

// layers deep abstracted view
case .selectedPlaylist:
if let selectedPlaylist = mainViewModel.selectedPlaylist {
SelectedPlaylistView(
showFlags: PlaylistShowFlags.none,
spotifyCache: spotifyCache,
avAudioPlayer: avAudioPlayer,
playlist: selectedPlaylist,
selectedArtist: $mainViewModel.selectedArtist,
selectedAlbum: $mainViewModel.selectedAlbum
)
} else {
Text("Unable to get selected playlist")
.font(.title)
}
case .selectedArtist:
if let artist = mainViewModel.selectedArtist {
ArtistView(spotifyCache: spotifyCache, artist: artist)
} else {
Text("Unable to get selected artist")
.font(.title)
}

// unimplemented views
default:
Text("Unknown error")
.font(.title)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.overlay {
RoundedRectangle(cornerRadius: 5)
.stroke(.fgTertiary, lineWidth: 0.5)
.allowsHitTesting(false)
}

// unimplemented views
default:
Text("Unknown error")
.font(.title)
if mainViewModel.showQueueView {
QueueElementView(avAudioPlayer: avAudioPlayer,
selectedArtist: $mainViewModel.selectedArtist)
.frame(maxHeight: .infinity)
.overlay {
RoundedRectangle(cornerRadius: 5)
.stroke(.fgTertiary, lineWidth: 0.5)
.allowsHitTesting(false)
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.overlay {
RoundedRectangle(cornerRadius: 5)
.stroke(.fgTertiary, lineWidth: 0.5)
.allowsHitTesting(false)
}

PlayingElementView(avAudioPlayer: avAudioPlayer,
selectedArtist: $mainViewModel.selectedArtist,
selectedAlbum: $mainViewModel.selectedAlbum)
selectedAlbum: $mainViewModel.selectedAlbum,
showQueueView: $mainViewModel.showQueueView)
}
}
.padding()
Expand Down

0 comments on commit b2a9e16

Please sign in to comment.