97 lines
3.7 KiB
Swift
97 lines
3.7 KiB
Swift
import Domain
|
|
import SwiftUI
|
|
|
|
struct ArtistDetailView: View {
|
|
let id: EntityID
|
|
|
|
@Environment(AppModel.self) private var app
|
|
@Environment(PlayerModel.self) private var player
|
|
@State private var artist: Artist?
|
|
@State private var albums: [Album] = []
|
|
@State private var topTracks: [Track] = []
|
|
|
|
var body: some View {
|
|
ScrollView {
|
|
VStack(alignment: .leading, spacing: 24) {
|
|
hero
|
|
if !topTracks.isEmpty {
|
|
VStack(alignment: .leading, spacing: 8) {
|
|
SectionHeader(title: "Top Songs")
|
|
TrackList(tracks: topTracks, subtitle: .album)
|
|
}
|
|
}
|
|
if !albums.isEmpty {
|
|
VStack(alignment: .leading, spacing: 12) {
|
|
SectionHeader(title: "Albums")
|
|
AlbumGrid(albums: albums, showsArtist: false)
|
|
}
|
|
}
|
|
}
|
|
.padding(.bottom, 24)
|
|
}
|
|
.ignoresSafeArea(edges: .top)
|
|
.modifier(ScrollRevealedTitle(title: artist?.name ?? "", threshold: 270))
|
|
.scrollEdgeEffectHidden(true, for: .top)
|
|
.toolbar {
|
|
if app.canFavorite(id) {
|
|
ToolbarItem(placement: .topBarTrailing) {
|
|
let isFavorite = app.favorites.contains(id)
|
|
Button(
|
|
isFavorite ? "Undo Favorite" as LocalizedStringKey : "Favorite",
|
|
systemImage: isFavorite ? "star.fill" : "star"
|
|
) {
|
|
app.toggleFavorite(id, kind: .artist)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.task(id: app.revision) {
|
|
artist = await app.library.artist(id)
|
|
albums = await app.library.albums(byArtist: id)
|
|
topTracks = await Array(app.library.tracks(byArtist: id).prefix(5))
|
|
}
|
|
}
|
|
|
|
private var hero: some View {
|
|
ArtworkView(artwork: artist?.artwork, shape: .rounded(0), pixelSize: 1024)
|
|
.containerRelativeFrame(.horizontal)
|
|
.visualEffect { content, proxy in
|
|
let pull = max(proxy.frame(in: .scrollView).minY, 0)
|
|
return content.scaleEffect(1 + pull / max(proxy.size.height, 1), anchor: .bottom)
|
|
}
|
|
.overlay(alignment: .bottom) {
|
|
LinearGradient(
|
|
stops: [
|
|
.init(color: .clear, location: 0),
|
|
.init(color: Color(.systemBackground).opacity(0.55), location: 0.55),
|
|
.init(color: Color(.systemBackground), location: 1),
|
|
],
|
|
startPoint: .top,
|
|
endPoint: .bottom
|
|
)
|
|
.frame(height: 200)
|
|
}
|
|
.overlay(alignment: .bottom) {
|
|
HStack(alignment: .bottom) {
|
|
Text(artist?.name ?? "")
|
|
.font(.largeTitle.bold())
|
|
.lineLimit(2)
|
|
.minimumScaleFactor(0.7)
|
|
Spacer()
|
|
Button {
|
|
Task { await player.shuffle(app.library.tracks(byArtist: id)) }
|
|
} label: {
|
|
Image(systemName: "play.fill")
|
|
.font(.title3)
|
|
.foregroundStyle(.white)
|
|
.frame(width: 48, height: 48)
|
|
.background(.tint, in: .circle)
|
|
}
|
|
.accessibilityLabel("Play")
|
|
}
|
|
.padding(.horizontal, Metrics.margin)
|
|
.padding(.bottom, 12)
|
|
}
|
|
}
|
|
}
|