Skip to content

Commit

Permalink
wip: refactored carousel views to use proper view models
Browse files Browse the repository at this point in the history
  • Loading branch information
Lee Jun Kit committed Jun 23, 2021
1 parent 7881f83 commit da11e3a
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 131 deletions.
4 changes: 4 additions & 0 deletions Spottie.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
475EE24A267DA451007BEBDC /* GreenPlayButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 475EE249267DA451007BEBDC /* GreenPlayButton.swift */; };
475EE24C267EBDE7007BEBDC /* SearchResultsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 475EE24B267EBDE7007BEBDC /* SearchResultsResponse.swift */; };
475EE24F267EBFEA007BEBDC /* WebAPIPagingObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 475EE24E267EBFEA007BEBDC /* WebAPIPagingObject.swift */; };
4764B39D26833B9900AE471E /* HoverState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4764B39C26833B9900AE471E /* HoverState.swift */; };
47C56F602679A789003EA20A /* PlayerCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C56F5F2679A789003EA20A /* PlayerCommands.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -147,6 +148,7 @@
475EE249267DA451007BEBDC /* GreenPlayButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GreenPlayButton.swift; sourceTree = "<group>"; };
475EE24B267EBDE7007BEBDC /* SearchResultsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsResponse.swift; sourceTree = "<group>"; };
475EE24E267EBFEA007BEBDC /* WebAPIPagingObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAPIPagingObject.swift; sourceTree = "<group>"; };
4764B39C26833B9900AE471E /* HoverState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HoverState.swift; sourceTree = "<group>"; };
47C56F5F2679A789003EA20A /* PlayerCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerCommands.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -320,6 +322,7 @@
475EE243267D6659007BEBDC /* ShortcutItem.swift */,
475EE247267D7784007BEBDC /* SearchField.swift */,
475EE249267DA451007BEBDC /* GreenPlayButton.swift */,
4764B39C26833B9900AE471E /* HoverState.swift */,
);
path = Components;
sourceTree = "<group>";
Expand Down Expand Up @@ -483,6 +486,7 @@
4730616526565841001E3A1F /* Library.swift in Sources */,
4730619926591F92001E3A1F /* VolumeChangedEvent.swift in Sources */,
4730619726591F14001E3A1F /* MetadataAvailableEvent.swift in Sources */,
4764B39D26833B9900AE471E /* HoverState.swift in Sources */,
4730617B265903A6001E3A1F /* EventBroker.swift in Sources */,
470201CA265CF9380030ECA9 /* ShuffleButton.swift in Sources */,
4730619326591EE1001E3A1F /* TrackChangedEvent.swift in Sources */,
Expand Down
68 changes: 28 additions & 40 deletions Spottie/Views/Components/CarouselRow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,63 +10,51 @@ import SwiftUI
struct CarouselRow: View {
let viewModel: ViewModel
let onItemPressed: (String) -> Void
let numItemsToShow: Int

var body: some View {
if viewModel.groupID.hasPrefix("podcast") {
EmptyView()
} else {
VStack(alignment: .leading) {
Text(viewModel.title)
.font(.title).bold()
VStack(alignment: .leading) {
Text(viewModel.title)
.font(.title).bold()
.padding(.leading)
viewModel.subtitle.map({
Text($0)
.font(.body)
.foregroundColor(.secondary)
.padding(.leading)
viewModel.subtitle.map({
Text($0)
.font(.body)
.foregroundColor(.secondary)
.padding(.leading)
.padding(.bottom, 8)
})
HStack(alignment: .top, spacing: 40) {
ForEach(viewModel.items) { item in
let vm = CarouselRowItem.ViewModel.init(item)
CarouselRowItem(viewModel: vm, onPlayButtonPressed: {
.padding(.bottom, 8)
})
HStack(alignment: .top, spacing: 40) {
ForEach(viewModel.getItemsToShow(requestedNumToShow: numItemsToShow)) { item in
CarouselRowItem(
vm: item,
onPlayButtonPressed: {
onItemPressed(item.id)
})
.onTapGesture {

}
}
.onTapGesture {
print("unimplemented")
}
}
.padding([.leading, .trailing])
}
.padding([.leading, .trailing])
}

}
}

extension CarouselRow {
enum RenderMode {
case circular
case normal
}

class ViewModel: ObservableObject {
var groupID: String
struct ViewModel: Identifiable {
var id: String
var title: String
var subtitle: String?
var items: [RecommendationItem]
var items: [CarouselRowItem.ViewModel]

init(_ recommendationGroup: RecommendationGroup, numberOfItemsToShow: Int) {
self.groupID = recommendationGroup.id

title = recommendationGroup.name
subtitle = recommendationGroup.tagline

let numItems = recommendationGroup.items.count
if (numItems < numberOfItemsToShow) {
items = recommendationGroup.items
func getItemsToShow(requestedNumToShow: Int) -> [CarouselRowItem.ViewModel] {
let numItems = items.count
if (numItems < requestedNumToShow) {
return items
} else {
items = Array(recommendationGroup.items[0...numberOfItemsToShow - 1])
return Array(items[0...requestedNumToShow - 1])
}
}
}
Expand Down
59 changes: 16 additions & 43 deletions Spottie/Views/Components/CarouselRowItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,22 @@ import SwiftUI
import SDWebImageSwiftUI

struct CarouselRowItem: View {
@ObservedObject var viewModel: ViewModel
var vm: ViewModel
var onPlayButtonPressed: () -> Void
@ObservedObject private var hoverState = HoverState()

var body: some View {
VStack(alignment: .leading) {
ZStack(alignment: .bottomTrailing) {
if viewModel.artworkIsCircle {
WebImage(url: viewModel.artworkURL)
if vm.artworkIsCircle {
WebImage(url: vm.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)
WebImage(url: vm.artworkURL)
.resizable()
.aspectRatio(1.0, contentMode: .fill)
.cornerRadius(5)
Expand All @@ -32,67 +33,39 @@ struct CarouselRowItem: View {
onPlayButtonPressed()
}
.offset(x: -16, y: -16)
.opacity(viewModel.isHovering ? 1.0 : 0.0)
.opacity(hoverState.isHovering ? 1.0 : 0.0)
.animation(.linear(duration: 0.1))
}

Text(viewModel.title)
Text(vm.title)
.lineLimit(1)
.foregroundColor(.primary)
.font(.headline)
.padding(.vertical, 4)
Text(viewModel.subtitle)
Text(vm.subtitle)
.lineLimit(2)
.foregroundColor(.secondary)
}
.frame(maxWidth: 200)
.padding()
.background(
Color(NSColor.alternatingContentBackgroundColors[1])
.opacity(viewModel.isHovering ? 1.0 : 0.3)
.opacity(hoverState.isHovering ? 1.0 : 0.3)
.animation(.linear(duration: 0.15))
)
.onHover { isHovered in
viewModel.isHovering = isHovered
hoverState.setIsHovering(isHovered)
}
}
}

extension CarouselRowItem {
class ViewModel: ObservableObject {
@Published var title: String
@Published var subtitle: String
@Published var artworkURL: URL
@Published var isHovering = false
@Published var artworkIsCircle = false

init(_ item: RecommendationItem) {
if let data = item.data {
switch data {
case let .album(album):
self.title = album.name
self.subtitle = album.artists[0].name
self.artworkURL = album.getArtworkURL()!
case let .artist(artist):
self.title = artist.name
self.subtitle = "Artist"
self.artworkURL = URL(string: artist.images[0].url)!
self.artworkIsCircle = true
case let.playlist(playlist):
self.title = playlist.name
self.subtitle = playlist.description ?? ""
self.artworkURL = URL(string: playlist.images[0].url)!
default:
self.title = ""
self.subtitle = ""
self.artworkURL = URL(string: "https://misc.scdn.co/liked-songs/liked-songs-640.png")!
}
} else {
self.title = ""
self.subtitle = ""
self.artworkURL = URL(string: "https://misc.scdn.co/liked-songs/liked-songs-640.png")!
}
}
struct ViewModel: Identifiable {
var id: String
var title: String
var subtitle: String
var artworkURL: URL
var artworkIsCircle = false
}
}

Expand Down
15 changes: 15 additions & 0 deletions Spottie/Views/Components/HoverState.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// HoverState.swift
// Spottie
//
// Created by Lee Jun Kit on 23/6/21.
//

import SwiftUI

class HoverState: ObservableObject {
@Published var isHovering = false
func setIsHovering(_ isHovering: Bool) {
self.isHovering = isHovering
}
}
4 changes: 2 additions & 2 deletions Spottie/Views/Components/ShortcutGrid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import SwiftUI
import SDWebImageSwiftUI

struct ShortcutGrid: View {
let items: [RecommendationItem]
let items: [CarouselRowItem.ViewModel]
let onItemPressed: (String) -> Void
var gridItemLayout = Array(repeating: GridItem(.flexible(), spacing: 20), count: 3)

Expand All @@ -22,7 +22,7 @@ struct ShortcutGrid: View {
ForEach(items) { item in
ShortcutItem(
itemHeight: 80,
viewModel: ShortcutItem.ViewModel(item),
viewModel: item,
onPlayButtonPressed: {
onItemPressed(item.id)
}
Expand Down
40 changes: 5 additions & 35 deletions Spottie/Views/Components/ShortcutItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import SDWebImageSwiftUI

struct ShortcutItem: View {
var itemHeight: CGFloat
var viewModel: ViewModel
var viewModel: CarouselRowItem.ViewModel
var onPlayButtonPressed: () -> Void

@State private var isHovering = false
@ObservedObject private var hoverState = HoverState()

var body: some View {
HStack {
Expand All @@ -29,45 +28,16 @@ struct ShortcutItem: View {
onPress: onPlayButtonPressed
)
.padding(.trailing)
.opacity(isHovering ? 1.0 : 0.0)
.opacity(hoverState.isHovering ? 1.0 : 0.0)
.animation(.linear(duration: 0.1))
}
.background(
Color(NSColor.alternatingContentBackgroundColors[1])
.opacity(isHovering ? 1.0 : 0.3)
.opacity(hoverState.isHovering ? 1.0 : 0.3)
.animation(.linear(duration: 0.1))
)
.onHover { hovering in
isHovering = hovering
}
}
}

extension ShortcutItem {
class ViewModel {
var title: String
var artworkURL: URL

init(_ item: RecommendationItem) {
if let data = item.data {
switch data {
case let .album(album):
self.title = album.name
self.artworkURL = album.getArtworkURL()!
case let .artist(artist):
self.title = artist.name
self.artworkURL = URL(string: artist.images[0].url)!
case let.playlist(playlist):
self.title = playlist.name
self.artworkURL = URL(string: playlist.images[0].url)!
case let .link(link):
self.title = link.name
self.artworkURL = URL(string: link.images[0].url)!
}
} else {
self.title = "Unknown"
self.artworkURL = URL(string: "https://misc.scdn.co/liked-songs/liked-songs-640.png")!
}
hoverState.setIsHovering(hovering)
}
}
}
Expand Down
Loading

0 comments on commit da11e3a

Please sign in to comment.