Skip to content

Commit

Permalink
wip implement search
Browse files Browse the repository at this point in the history
  • Loading branch information
Lee Jun Kit committed Jun 23, 2021
1 parent 8ef1333 commit 7881f83
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 47 deletions.
21 changes: 18 additions & 3 deletions Spottie/Backend/HTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,24 @@ import Foundation
import Combine

struct HTTPClient {
enum APIError: Error {
case unknown
case contentTypeError
}

struct Response<T> {
let value: T?
let value: T
let response: URLResponse
}

func run<T: Decodable>(_ request: URLRequest, _ decoder: JSONDecoder = JSONDecoder()) -> AnyPublisher<Response<T>, Error> {
return URLSession.shared
.dataTaskPublisher(for: request)
.tryMap { result -> Response<T> in
if T.self == Nothing.self {
return Response(value: Nothing() as! T, response: result.response)
}

let response = result.response as! HTTPURLResponse
let contentType = response.allHeaderFields["Content-Type"] as? String

Expand All @@ -27,10 +36,16 @@ struct HTTPClient {
return Response(value: value, response: result.response)
}
}

return Response(value: nil, response: result.response)
throw APIError.contentTypeError
}
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}

func runWithoutDecoding(_ request: URLRequest) -> AnyPublisher<Never, URLError> {
return URLSession.shared.dataTaskPublisher(for: request)
.ignoreOutput()
.eraseToAnyPublisher()
}
}
8 changes: 4 additions & 4 deletions Spottie/Backend/SpotifyAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ extension SpotifyAPI {
return client.run(req).map(\.value).eraseToAnyPublisher()
}

static func getPersonalizedRecommendations() -> AnyPublisher<PersonalizedRecommendationsResponse?, Error> {
static func getPersonalizedRecommendations() -> AnyPublisher<RecommendationsResponse?, Error> {
// get the current date
let date = Date()
let formatter = ISO8601DateFormatter()
Expand Down Expand Up @@ -137,9 +137,9 @@ extension SpotifyAPI {
return client.run(req, decoder).map(\.value).eraseToAnyPublisher()
}

static func search() -> AnyPublisher<SearchResultsResponse, Error> {
static func search(_ term: String) -> AnyPublisher<SearchResultsResponse?, Error> {
let queryItems = [
URLQueryItem(name: "q", value: "akmu"),
URLQueryItem(name: "q", value: term),
URLQueryItem(name: "type", value: "album,artist,playlist,track"),
URLQueryItem(name: "market", value: "from_token")
]
Expand All @@ -155,6 +155,6 @@ extension SpotifyAPI {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase;

return client.run(req, decoder).map(\.value).eraseToAnyPublisher()
return client.run(req, decoder).map(\.value).print().eraseToAnyPublisher()
}
}
2 changes: 1 addition & 1 deletion Spottie/Backend/Types/API/SearchResultsResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation

struct SearchResultsResponse: Decodable {
let albums: WebAPIPagingObject<WebAPISimplifiedAlbumObject>
let artists: WebAPIPagingObject<WebAPISimplifiedAlbumObject>
let artists: WebAPIPagingObject<WebAPISimplifiedArtistObject>
let tracks: WebAPIPagingObject<WebAPITrackObject>
let playlists: WebAPIPagingObject<WebAPIPlaylistObject>
}
4 changes: 2 additions & 2 deletions Spottie/Backend/Types/WebAPI/WebAPIPagingObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ struct WebAPIPagingObject<T: Decodable>: Decodable {
let limit: Int
let offset: Int
let total: Int
let next: String
let previous: String
let next: String?
let previous: String?
}
7 changes: 0 additions & 7 deletions Spottie/Views/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ enum Screen: Hashable {

struct ContentView<M: PlayerStateProtocol>: View {
@State var screen: Screen? = .home
@State var searchText = ""

var body: some View {
VStack {
Expand All @@ -25,12 +24,6 @@ struct ContentView<M: PlayerStateProtocol>: View {
.frame(height: 66)
.padding()
}
.toolbar {
ToolbarItem {
SearchField(search: $searchText)
.frame(minWidth: 100, idealWidth: 200, maxWidth: .infinity)
}
}
}
}

Expand Down
61 changes: 43 additions & 18 deletions Spottie/Views/Home.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,57 @@ import Combine

struct Home: View {
@ObservedObject var viewModel: ViewModel = ViewModel()

// search
@State private var searchText = ""
private var relay = PassthroughSubject<String, Never>()
private var debouncedPublisher: AnyPublisher<String, Never>

init() {
self.debouncedPublisher = relay
.debounce(for: 0.5, scheduler: DispatchQueue.main)
.eraseToAnyPublisher()
}

var body: some View {
GeometryReader { reader in
ScrollView(.vertical) {
LazyVStack(alignment: .leading) {
ForEach(viewModel.recommendationGroups) { group in
if group.id == "shortcuts" {
ShortcutGrid(
items: group.items,
onItemPressed: viewModel.load
)
.padding()
} else if group.items.count > 0 {
let vm = CarouselRow.ViewModel.init(group,
numberOfItemsToShow: numberOfItemsToShowInRow(reader)
)

CarouselRow(
viewModel: vm,
onItemPressed: viewModel.load
)
.padding()
if searchText.isEmpty {
LazyVStack(alignment: .leading) {
ForEach(viewModel.recommendationGroups) { group in
if group.id == "shortcuts" {
ShortcutGrid(
items: group.items,
onItemPressed: viewModel.load
)
.padding()
} else if group.items.count > 0 {
let vm = CarouselRow.ViewModel.init(group,
numberOfItemsToShow: numberOfItemsToShowInRow(reader)
)

CarouselRow(
viewModel: vm,
onItemPressed: viewModel.load
)
.padding()
}
}
}
} else {
Search(viewModel: Search.ViewModel(searchTermPublisher: debouncedPublisher))
}
}
}
.toolbar {
ToolbarItem {
SearchField(search: $searchText)
.frame(minWidth: 100, idealWidth: 200, maxWidth: .infinity)
}
}
.onChange(of: searchText) { text in
relay.send(text)
}
}

func numberOfItemsToShowInRow(_ reader: GeometryProxy) -> Int {
Expand Down
32 changes: 30 additions & 2 deletions Spottie/Views/Search.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,43 @@
//

import SwiftUI
import Combine

struct Search: View {
@StateObject var viewModel: ViewModel
var body: some View {
Text("Hello Search")
ScrollView {
LazyVStack(alignment: .leading) {

}
}
}
}

extension Search {
// The trick to get updates as the NSSearchField is updated
// is to create a publisher from onChange of searchText
// https://rhonabwy.com/2021/02/07/integrating-swiftui-bindings-and-combine/
class ViewModel: ObservableObject {
@Published var results: SearchResultsResponse?

init(searchTermPublisher: AnyPublisher<String, Never>) {
searchTermPublisher
.debounce(for: 0.5, scheduler: DispatchQueue.main)
.map {
SpotifyAPI.search($0)
.replaceError(with: nil)
}
.switchToLatest()
.receive(on: DispatchQueue.main)
.assign(to: &$results)
}
}
}

struct Search_Previews: PreviewProvider {
static let vm = Search.ViewModel(searchTermPublisher: Just("Hello").eraseToAnyPublisher())
static var previews: some View {
Search()
Search(viewModel: vm)
}
}
11 changes: 1 addition & 10 deletions Spottie/Views/Sidebar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,7 @@ struct Sidebar: View {
tag: Screen.home,
selection: $state,
label: {
Label("Home", systemImage: "house" )
}
)
NavigationLink(
destination: Search(),
tag: Screen.search,
selection: $state,
label: {
Label("Search", systemImage: "magnifyingglass")
Label("Home", systemImage: "house")
}
)
NavigationLink(
Expand All @@ -38,7 +30,6 @@ struct Sidebar: View {
)
}
.listStyle(SidebarListStyle())
.navigationTitle("Spottie")
}
}

Expand Down

0 comments on commit 7881f83

Please sign in to comment.