Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions flo/AlbumViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ class AlbumViewModel: ObservableObject {
return AlbumService.shared.getAlbumCover(
artistName: artistName, albumName: albumName, albumId: id, albumCover: albumCover)
}

func getPlaylistCoverArt(id: String, coverArtId: String? = nil) -> String {
let artId = coverArtId ?? id
return AlbumService.shared.getPlaylistCover(playlistId: artId)
}

func shareAlbum(description: String, completion: @escaping (String) -> Void) {
AlbumService.shared.share(albumId: self.album.id, description: description, downloadable: false)
Expand Down
54 changes: 44 additions & 10 deletions flo/PlaylistDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,39 @@

import SwiftUI

struct PlaylistCoverImageView: View {
let pathOrUrlString: String

var body: some View {
if pathOrUrlString.hasPrefix("http://") || pathOrUrlString.hasPrefix("https://") {
AsyncImage(url: URL(string: pathOrUrlString)) { phase in
switch phase {
case .success(let image):
image
.resizable()
.aspectRatio(contentMode: .fit)
case .failure, .empty:
placeholderImage
@unknown default:
placeholderImage
}
}
} else if let uiImage = UIImage(contentsOfFile: pathOrUrlString) {
Image(uiImage: uiImage)
.resizable()
.aspectRatio(contentMode: .fit)
} else {
placeholderImage
}
}

private var placeholderImage: some View {
Image(uiImage: UIImage(named: "placeholder") ?? UIImage())
.resizable()
.aspectRatio(contentMode: .fit)
}
}

struct PlaylistDetailView: View {
@EnvironmentObject private var viewModel: AlbumViewModel
@EnvironmentObject private var playerViewModel: PlayerViewModel
Expand All @@ -18,17 +51,18 @@ struct PlaylistDetailView: View {
var body: some View {
ScrollView {
VStack {
if let image = UIImage(named: "placeholder") {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 300, height: 300)
.clipShape(
RoundedRectangle(cornerRadius: 10, style: .continuous)
PlaylistCoverImageView(
pathOrUrlString: viewModel.getPlaylistCoverArt(
id: viewModel.playlist.id,
coverArtId: viewModel.playlist.coverArtId
)
.shadow(radius: 5)
.padding(.top, 10)
}
)
.frame(width: 300, height: 300)
.clipShape(
RoundedRectangle(cornerRadius: 10, style: .continuous)
)
.shadow(radius: 5)
.padding(.top, 10)

Text(viewModel.playlist.name)
.customFont(.title)
Expand Down
13 changes: 11 additions & 2 deletions flo/Shared/Models/Playlist.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct Playlist: Codable, Identifiable, Hashable, Playable {
let isPublic: Bool
let ownerName: String
let artist: String
let coverArtId: String?
var songs: [Song] = []

enum CodingKeys: String, CodingKey {
Expand All @@ -22,18 +23,25 @@ struct Playlist: Codable, Identifiable, Hashable, Playable {
case comment
case isPublic = "public"
case ownerName
case coverArtId
case songs
}

init(
id: String = "", name: String = "", comment: String = "", isPublic: Bool = false,
ownerName: String = "", songs: [Song] = []
id: String = "",
name: String = "",
comment: String = "",
isPublic: Bool = false,
ownerName: String = "",
coverArtId: String? = nil,
songs: [Song] = []
) {
self.id = id
self.name = name
self.comment = comment
self.isPublic = isPublic
self.ownerName = ownerName
self.coverArtId = coverArtId
self.songs = songs
self.artist = ownerName
}
Expand All @@ -46,6 +54,7 @@ struct Playlist: Codable, Identifiable, Hashable, Playable {
self.comment = try container.decode(String.self, forKey: .comment)
self.isPublic = try container.decode(Bool.self, forKey: .isPublic)
self.ownerName = try container.decode(String.self, forKey: .ownerName)
self.coverArtId = try container.decodeIfPresent(String.self, forKey: .coverArtId)
self.songs = try container.decodeIfPresent([Song].self, forKey: .songs) ?? []
self.artist = try container.decode(String.self, forKey: .ownerName)
}
Expand Down
13 changes: 13 additions & 0 deletions flo/Shared/Services/AlbumService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,19 @@ class AlbumService {
"\(UserDefaultsManager.serverBaseURL)\(API.SubsonicEndpoint.coverArt)\(AuthService.shared.getCreds(key: "subsonicToken"))&id=al-\(albumId)&size=300"
}
}

func getPlaylistCover(playlistId: String) -> String {
let target = "Media/Various Artists/\(playlistId)/cover.png"

if LocalFileManager.shared.fileExists(fileName: target) {
return LocalFileManager.shared.fileURL(for: target)?.path ?? ""
} else if let cached = CoverArtCacheManager.shared.cachedFilePath(albumId: playlistId) {
return cached
} else {
let artId = playlistId.hasPrefix("pl-") ? playlistId : "pl-\(playlistId)"
return "\(UserDefaultsManager.serverBaseURL)\(API.SubsonicEndpoint.coverArt)\(AuthService.shared.getCreds(key: "subsonicToken"))&id=\(artId)&size=300"
}
}

func downloadAlbumCover(
artistName: String, albumId: String, albumName: String,
Expand Down