diff --git a/Spottie/Backend/SpotifyAPI.swift b/Spottie/Backend/SpotifyAPI.swift index 3eff921..3c6b2da 100644 --- a/Spottie/Backend/SpotifyAPI.swift +++ b/Spottie/Backend/SpotifyAPI.swift @@ -31,7 +31,7 @@ extension SpotifyAPI { var req = URLRequest(url: urlComponents.url!) req.httpMethod = "POST" - return client.run(req).print().map(\.value).eraseToAnyPublisher() + return client.run(req).map(\.value).eraseToAnyPublisher() } static func togglePlayPause() -> AnyPublisher { @@ -49,19 +49,19 @@ extension SpotifyAPI { static func resume() -> AnyPublisher { var req = URLRequest(url: base.appendingPathComponent("/player/resume")) req.httpMethod = "POST" - return client.run(req).print().map(\.value).eraseToAnyPublisher() + return client.run(req).map(\.value).eraseToAnyPublisher() } static func previousTrack() -> AnyPublisher { var req = URLRequest(url: base.appendingPathComponent("/player/prev")) req.httpMethod = "POST" - return client.run(req).print().map(\.value).eraseToAnyPublisher() + return client.run(req).map(\.value).eraseToAnyPublisher() } static func nextTrack() -> AnyPublisher { var req = URLRequest(url: base.appendingPathComponent("/player/next")) req.httpMethod = "POST" - return client.run(req).print().map(\.value).eraseToAnyPublisher() + return client.run(req).map(\.value).eraseToAnyPublisher() } static func seek(posMs: Int) -> AnyPublisher { @@ -71,7 +71,7 @@ extension SpotifyAPI { var req = URLRequest(url: urlComponents.url!) req.httpMethod = "POST" - return client.run(req).print().map(\.value).eraseToAnyPublisher() + return client.run(req).map(\.value).eraseToAnyPublisher() } static func setVolume(volumePercent: Float) -> AnyPublisher { @@ -82,7 +82,7 @@ extension SpotifyAPI { var req = URLRequest(url: urlComponents.url!) req.httpMethod = "POST" - return client.run(req).print().map(\.value).eraseToAnyPublisher() + return client.run(req).map(\.value).eraseToAnyPublisher() } static func setShuffle(shuffle: Bool) -> AnyPublisher { @@ -92,7 +92,7 @@ extension SpotifyAPI { var req = URLRequest(url: urlComponents.url!) req.httpMethod = "POST" - return client.run(req).print().map(\.value).eraseToAnyPublisher() + return client.run(req).map(\.value).eraseToAnyPublisher() } static func setRepeatMode(mode: RepeatMode) -> AnyPublisher { @@ -102,12 +102,17 @@ extension SpotifyAPI { var req = URLRequest(url: urlComponents.url!) req.httpMethod = "POST" - return client.run(req).print().map(\.value).eraseToAnyPublisher() + return client.run(req).map(\.value).eraseToAnyPublisher() } static func getPersonalizedRecommendations() -> AnyPublisher { + // get the current date + let date = Date() + let formatter = ISO8601DateFormatter() + formatter.formatOptions.insert(.withFractionalSeconds) + let queryItems = [ - URLQueryItem(name: "timestamp", value: "2021-06-07T10:54:29.467Z"), + URLQueryItem(name: "timestamp", value: formatter.string(from: date)), URLQueryItem(name: "platform", value: "web"), URLQueryItem(name: "content_limit", value: "10"), URLQueryItem(name: "limit", value: "20"), @@ -129,6 +134,6 @@ extension SpotifyAPI { let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase; - return client.run(req, decoder).print().map(\.value).eraseToAnyPublisher() + return client.run(req, decoder).map(\.value).eraseToAnyPublisher() } } diff --git a/Spottie/Backend/Types/API/RecommendationGroup.swift b/Spottie/Backend/Types/API/RecommendationGroup.swift index 0c0c514..e272f2b 100644 --- a/Spottie/Backend/Types/API/RecommendationGroup.swift +++ b/Spottie/Backend/Types/API/RecommendationGroup.swift @@ -10,6 +10,7 @@ import Foundation struct RecommendationGroup: Decodable, Hashable, Identifiable { var id: String var name: String + var tagline: String? var rendering: String var items: [RecommendationItem] diff --git a/Spottie/Views/Carousel/CarouselRow.swift b/Spottie/Views/Carousel/CarouselRow.swift index 4f0b83f..2281cc0 100644 --- a/Spottie/Views/Carousel/CarouselRow.swift +++ b/Spottie/Views/Carousel/CarouselRow.swift @@ -14,14 +14,17 @@ struct CarouselRow: View { Text(viewModel.title) .font(.title) .padding(.leading) - Text(viewModel.subtitle) - .font(.body) - .foregroundColor(.secondary) - .padding(.leading) - .padding(.bottom, 8) + viewModel.subtitle.map({ + Text($0) + .font(.body) + .foregroundColor(.secondary) + .padding(.leading) + .padding(.bottom, 8) + }) HStack(alignment: .top, spacing: 40) { ForEach(viewModel.items) { item in - CarouselRowItem(viewModel: CarouselRowItem.ViewModel.init(item)) + let vm = CarouselRowItem.ViewModel.init(item, artworkIsCircular: viewModel.renderMode == .circular) + CarouselRowItem(viewModel: vm) .onTapGesture { viewModel.onItemPressed(item.id) } @@ -33,9 +36,15 @@ struct CarouselRow: View { } extension CarouselRow { + enum RenderMode { + case circular + case normal + } + class ViewModel: ObservableObject { + @Published var renderMode: RenderMode @Published var title: String - @Published var subtitle = "Unwind with these calming playlists." + @Published var subtitle: String? @Published var items: [RecommendationItem] let onItemPressed: (String) -> Void @@ -43,6 +52,13 @@ extension CarouselRow { self.onItemPressed = onItemPressed title = recommendationGroup.name + subtitle = recommendationGroup.tagline + + if (recommendationGroup.id == "home-personalized[favorite-artists]") { + renderMode = .circular + } else { + renderMode = .normal + } let numItems = recommendationGroup.items.count if (numItems < numberOfItemsToShow) { diff --git a/Spottie/Views/Carousel/CarouselRowItem.swift b/Spottie/Views/Carousel/CarouselRowItem.swift index a74f9bc..0ccbec1 100644 --- a/Spottie/Views/Carousel/CarouselRowItem.swift +++ b/Spottie/Views/Carousel/CarouselRowItem.swift @@ -13,10 +13,19 @@ struct CarouselRowItem: View { var body: some View { VStack(alignment: .leading) { - WebImage(url: viewModel.artworkURL) - .resizable() - .aspectRatio(1.0, contentMode: .fill) - .cornerRadius(5) + if viewModel.artworkIsCircle { + WebImage(url: viewModel.artworkURL) + .resizable() + .aspectRatio(1.0, contentMode: .fill) + .clipShape(Circle()) + .overlay(Circle().stroke(Color.white, lineWidth: 4.0)) + .shadow(radius: 7) + } else { + WebImage(url: viewModel.artworkURL) + .resizable() + .aspectRatio(1.0, contentMode: .fill) + .cornerRadius(5) + } Text(viewModel.title) .lineLimit(1) .foregroundColor(.primary) @@ -44,8 +53,11 @@ extension CarouselRowItem { @Published var subtitle: String @Published var artworkURL: URL @Published var isHovering = false + @Published var artworkIsCircle = false - init(_ item: RecommendationItem) { + init(_ item: RecommendationItem, artworkIsCircular: Bool) { + artworkIsCircle = artworkIsCircular + if let data = item.data { switch data { case let .album(album): @@ -54,7 +66,7 @@ extension CarouselRowItem { self.artworkURL = album.getArtworkURL()! case let .artist(artist): self.title = artist.name - self.subtitle = artist.name + self.subtitle = "Artist" self.artworkURL = URL(string: artist.images[0].url)! case let.playlist(playlist): self.title = playlist.name