Skip to content

Commit

Permalink
Improve artist view (#64)
Browse files Browse the repository at this point in the history
* Improve click target for context button

* Make number optional

* Add a better track list to artist view

* Make whole album view scrollable

* Remove list usage

* Improve padding and layout of view

* Imrpove spacing in artists view
  • Loading branch information
robbevp authored Feb 4, 2024
1 parent f50d1e3 commit 8345707
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 49 deletions.
2 changes: 1 addition & 1 deletion accentor/Model/Track.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Foundation
import GRDB

struct Track: Identifiable, Equatable, Codable, FetchableRecord, PersistableRecord {
struct Track: Identifiable, Equatable, Hashable, Codable, FetchableRecord, PersistableRecord {
// Generic properties
var id: Int64
var createdAt: Date
Expand Down
62 changes: 32 additions & 30 deletions accentor/View/Albums/AlbumView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import GRDBQuery

struct AlbumView: View {
@EnvironmentStateObject private var viewModel: AlbumViewModel
@Environment(\.defaultMinListRowHeight) var minRowHeight

init(id: Album.ID) {
_viewModel = EnvironmentStateObject {
Expand All @@ -19,42 +20,44 @@ struct AlbumView: View {

var body: some View {
if let album = viewModel.albumInfo?.album {
VStack {
CachedImage(imageURL: album.image250) {
GeometryReader { geometry in
ZStack {
Rectangle().fill(.gray)
Image(systemName: "music.note").font(.largeTitle)
}.frame(width: geometry.size.width, height: geometry.size.width)
}
}.scaledToFit()
.frame(maxWidth: 250)
.clipShape(RoundedRectangle(cornerRadius: 4))
.shadow(radius: 6, x: -3, y: 3)

Text(album.title).font(.title)
Text(AlbumArtist.constructAlbumArtistText(viewModel.albumInfo?.albumArtists)).foregroundStyle(Color.accentColor)

HStack {
Button(action: viewModel.playAlbum, label: {
Label("Play", systemImage: "play.fill")
})
ScrollView {
VStack {
CachedImage(imageURL: album.image250) {
GeometryReader { geometry in
ZStack {
Rectangle().fill(.gray)
Image(systemName: "music.note").font(.largeTitle)
}.frame(width: geometry.size.width, height: geometry.size.width)
}
}.scaledToFit()
.frame(maxWidth: 250)
.clipShape(RoundedRectangle(cornerRadius: 4))
.shadow(radius: 6, x: -3, y: 3)

Button(action: viewModel.shuffleAlbum, label: {
Label("Shuffle", systemImage: "shuffle")
})
}.buttonStyle(.borderedProminent)
List {
Text(album.title).font(.title)
Text(AlbumArtist.constructAlbumArtistText(viewModel.albumInfo?.albumArtists)).foregroundStyle(Color.accentColor)

HStack {
Button(action: viewModel.playAlbum, label: {
Label("Play", systemImage: "play.fill")
})

Button(action: viewModel.shuffleAlbum, label: {
Label("Shuffle", systemImage: "shuffle")
})
}.buttonStyle(.borderedProminent)
Section(content: {
Divider()
ForEach(viewModel.albumInfo!.tracks, id: \.track.id) { trackInfo in
TrackRowView(track: trackInfo.track, trackArtists: trackInfo.trackArtists)
TrackRowView(track: trackInfo.track, trackArtists: trackInfo.trackArtists, showNumber: true).padding(.horizontal, 12)
Divider()
}
}, footer: {
// Add padding here, so the view scrolls under the player
Text(viewModel.tracksStats).padding(.bottom, 75)
Text(viewModel.tracksStats).frame(maxWidth: .infinity, alignment: .leading).padding(.horizontal, 12).font(.caption2).foregroundStyle(Color.gray)
})
}.listStyle(.plain)
}.padding(.top, 10)
}.padding(EdgeInsets(top: 10, leading: 0, bottom: 75, trailing: 0))
}
.navigationTitle(album.title)
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
Expand All @@ -71,7 +74,6 @@ struct AlbumView: View {
}
})
}

} else {
ProgressView()
}
Expand Down
35 changes: 23 additions & 12 deletions accentor/View/Artists/ArtistView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@ import GRDBQuery

struct ArtistView: View {
@EnvironmentStateObject private var viewModel: ArtistViewModel
@Environment(\.defaultMinListRowHeight) var minRowHeight

init(id: Artist.ID) {
_viewModel = EnvironmentStateObject {
ArtistViewModel(database: $0.appDatabase, id: id)
}
}

var body: some View {
if let artist = viewModel.artistInfo?.artist {
ScrollView {
VStack(alignment: .leading) {
HStack {
HStack(alignment: .bottom) {
if (artist.image250 != nil) {
CachedImage(imageURL: artist.image250) {
ZStack {
Expand All @@ -30,23 +31,33 @@ struct ArtistView: View {
}
}.frame(maxWidth: 250, maxHeight: 250)
}
Text(artist.name)
}
Section("Albums") {
Text(artist.name).font(.headline)
}.padding(10)
Section(content: {
ScrollView(.horizontal) {
LazyHStack(spacing: 5) {
ForEach(viewModel.artistInfo!.albums) { item in
AlbumCard(id: item.id).frame(width: 200, height: 250)
}
}
}.padding(.horizontal, 8)
}
}, header: {
Text("Albums").padding(.horizontal, 12).font(.subheadline)
})
Section(content: {
ForEach(viewModel.artistInfo!.tracks, id: \.track.id) { trackInfo in
TrackRowView(track: trackInfo.track, trackArtists: trackInfo.trackArtists).padding(.horizontal, 12)
Divider()
}
}
Text("Tracks")
ForEach(viewModel.artistInfo!.tracks) { track in
Text(track.title)
}
}
}, header: {
Text("Tracks").padding(.horizontal, 12).font(.subheadline)
Divider()
})
}.padding(EdgeInsets(top: 10, leading: 0, bottom: 75, trailing: 0))
}.navigationTitle(artist.name)
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
} else {
ProgressView()
}
Expand Down
12 changes: 10 additions & 2 deletions accentor/View/Artists/ArtistViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@ import Combine
import GRDB

final class ArtistViewModel: ObservableObject {
struct TrackInfo: Decodable {
var track: Track
var trackArtists: [TrackArtist]
}

struct ArtistInfo: Decodable, FetchableRecord {
var artist: Artist
var tracks: [Track]
var tracks: [TrackInfo]
var albums: [Album]
}

Expand All @@ -23,7 +28,10 @@ final class ArtistViewModel: ObservableObject {
init(database: AppDatabase, id: Album.ID) {
self.database = database
self.observationCancellable = ValueObservation
.tracking(Artist.filter(key: id).including(all: Artist.tracks.order(Track.Columns.normalizedTitle)).including(all: Artist.albums.all().orderByRelease()).asRequest(of: ArtistInfo.self).fetchOne)
.tracking(Artist.filter(key: id)
.including(all: Artist.tracks.order(Track.Columns.normalizedTitle).distinct().including(all: Track.trackArtists))
.including(all: Artist.albums.all().orderByRelease())
.asRequest(of: ArtistInfo.self).fetchOne)
.publisher(in: database.reader, scheduling: .immediate)
.sink(
receiveCompletion: { _ in /* ignore error */ },
Expand Down
4 changes: 2 additions & 2 deletions accentor/View/Artists/ArtistsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct ArtistsView: View {
}

let columns = [
GridItem(.adaptive(minimum: 130))
GridItem(.adaptive(minimum: 162, maximum: 252))
]

var body: some View {
Expand All @@ -30,7 +30,7 @@ struct ArtistsView: View {
ArtistCard(artist: artist)
}.buttonStyle(PlainButtonStyle())
}
}
}.padding(EdgeInsets(top: 20, leading: 30, bottom: 65, trailing: 30))
}.navigationTitle("Artists")
.searchable(text: $viewModel.searchTerm)
}
Expand Down
9 changes: 7 additions & 2 deletions accentor/View/TrackRow/TrackRowView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,20 @@ import GRDBQuery

struct TrackRowView: View {
@EnvironmentStateObject private var viewModel: TrackRowViewModel
let showNumber: Bool

init(track: Track, trackArtists: [TrackArtist]) {
init(track: Track, trackArtists: [TrackArtist], showNumber: Bool = false) {
self.showNumber = showNumber
_viewModel = EnvironmentStateObject {
TrackRowViewModel(database: $0.appDatabase, player: $0.player, track: track, trackArtists: trackArtists)
}
}

var body: some View {
HStack {
Text(String(viewModel.track.number)).padding(.trailing, 20)
if (showNumber) {
Text(String(viewModel.track.number)).padding(.trailing, 20)
}
VStack(alignment: .leading) {
Text(viewModel.track.title).foregroundStyle(Color.black)
Text(TrackArtist.constructTrackArtistText(viewModel.trackArtists))
Expand Down Expand Up @@ -50,6 +54,7 @@ struct TrackRowView: View {
TrackActions(viewModel: viewModel)
} label: {
ZStack {
Circle().fill(Color(white: 0, opacity: 0)).frame(width: 30, height: 30)
Label("Actions", systemImage: "ellipsis")
.foregroundStyle(Color.accentColor)
.labelStyle(.iconOnly)
Expand Down

0 comments on commit 8345707

Please sign in to comment.