feat: add HomeView with recently added list and library stats

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat/music-streaming
Laurent 1 month ago
parent 4a3dd23e57
commit 09be0460d4
  1. 127
      Music/Views/HomeView.swift

@ -0,0 +1,127 @@
import SwiftUI
import Charts
struct HomeView: View {
let recentTracks: [Track]
let trackCount: Int
let totalDuration: Double
let monthlyAdditions: [MonthlyCount]
let onTrackDoubleClick: (Track) -> Void
let onShowAll: () -> Void
var body: some View {
HStack(alignment: .top, spacing: 0) {
recentlyAddedPanel
.frame(maxWidth: .infinity, maxHeight: .infinity)
Divider()
statsPanel
.frame(minWidth: 300, maxWidth: 300, maxHeight: .infinity)
}
}
private var recentlyAddedPanel: some View {
VStack(alignment: .leading, spacing: 0) {
HStack {
Text("Recently Added")
.font(.title2.weight(.semibold))
Spacer()
Button("Show All", action: onShowAll)
.buttonStyle(.plain)
.foregroundStyle(.secondary)
}
.padding(.horizontal, 16)
.padding(.top, 12)
.padding(.bottom, 8)
ScrollView {
LazyVStack(alignment: .leading, spacing: 0) {
ForEach(recentTracks) { track in
VStack(alignment: .leading, spacing: 2) {
Text(track.title)
.font(.system(size: 13, weight: .medium))
.lineLimit(1)
Text(track.artist)
.font(.system(size: 12))
.foregroundStyle(.secondary)
.lineLimit(1)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.vertical, 4)
.padding(.horizontal, 16)
.contentShape(Rectangle())
.onTapGesture(count: 2) {
onTrackDoubleClick(track)
}
}
}
}
}
}
private var statsPanel: some View {
VStack(alignment: .leading, spacing: 24) {
VStack(alignment: .leading, spacing: 12) {
Text("Library")
.font(.title2.weight(.semibold))
VStack(alignment: .leading, spacing: 8) {
Label(
"\(trackCount.formatted()) tracks",
systemImage: "music.note"
)
.font(.system(size: 13))
Label(
Self.formatTotalDuration(totalDuration),
systemImage: "clock"
)
.font(.system(size: 13))
}
}
if !monthlyAdditions.isEmpty {
VStack(alignment: .leading, spacing: 8) {
Text("Added per Month")
.font(.system(size: 12, weight: .medium))
.foregroundStyle(.secondary)
Chart(monthlyAdditions, id: \.month) { item in
BarMark(
x: .value("Month", item.month, unit: .month),
y: .value("Tracks", item.count)
)
.foregroundStyle(Color.accentColor)
}
.chartXAxis {
AxisMarks(values: .stride(by: .month, count: 2)) { value in
AxisValueLabel(format: .dateTime.month(.abbreviated))
}
}
.frame(height: 150)
}
}
Spacer()
}
.padding(16)
}
private static func formatTotalDuration(_ seconds: Double) -> String {
guard seconds.isFinite, seconds >= 0 else { return "0 minutes" }
let totalMinutes = Int(seconds) / 60
let hours = totalMinutes / 60
let days = hours / 24
let remainingHours = hours % 24
if days > 0 {
return "\(days) days, \(remainingHours) hours"
} else if hours > 0 {
let remainingMinutes = totalMinutes % 60
return "\(hours) hours, \(remainingMinutes) minutes"
} else {
return "\(totalMinutes) minutes"
}
}
}
Loading…
Cancel
Save