[UIKit] Spotify Clone: Add to Playlist

Junyoung Park·2022년 9월 11일
0

UIKit

목록 보기
23/142
post-thumbnail

Building Spotify App in Swift 5 & UIKit - Part 23 - Add to Playlist (Xcode 12, 2021, Swift 5)

Spotify Clone: Add to Playlist

구현 목표

  • 음원을 플레이리스트에 추가하기

구현 태스크

  1. HomeViewController의 음원 LongTapGesture 추가
  2. 현재 유저의 LibraryPlaylistViewControlleractionSheet 형태 전달
  3. 스포티파이 API를 통해 해당 음원, 해당 플레이리스트 사용해 플레이리스트 추가

핵심 코드

@objc private func didLongPress(_ gesture: UILongPressGestureRecognizer) {
        guard gesture.state == .began else {
            return
        }
        
        let touchPoint = gesture.location(in: collectionView)
        guard
            let indexPath = collectionView.indexPathForItem(at: touchPoint),
            indexPath.section == 2 else {
            return
        }
        let model = tracks[indexPath.row]
        let actionSheet = UIAlertController(title: model.name, message: "Would you like to add this track to a playlist?", preferredStyle: .actionSheet)
        actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        actionSheet.addAction(UIAlertAction(title: "Add to Playlist", style: .default, handler: { [weak self] _ in
            guard let self = self else { return }
            let vc = LibraryPlaylistsViewController()
            vc.selectionHandler = { playlist in
                APICaller.shared.addTrackToPlaylist(track: model, playlist: playlist) { success in
                    let alert = UIAlertController(title: "Add to Playlist", message: success ? "Success" : "Fail", preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
                    self.present(alert, animated: true)
                }
            }
            vc.title = "Select Playlist"
            self.present(UINavigationController(rootViewController: vc), animated: true)
        }))
        present(actionSheet, animated: true)
    }
  • 컬렉션 뷰 자체에 LognTapGesture 추가
  • indexPath.section이 2, 즉 음원 컬렉션 뷰일 때에만 사용
  • actionSheet 형태로 LibraryPlaylistViewController 전달
  • selectionHandler에 선택된 플레이리스트 정보 전달 및 API 함수 호출
var selectionHandler: ((Playlist) -> ())?
...
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let playlist = playlists[indexPath.row]

        guard selectionHandler == nil else {
            self.selectionHandler?(playlist)
            self.dismiss(animated: true, completion: nil)
            return
        }
        
        let vc = PlaylistViewController(playlist: playlist)
        vc.navigationItem.largeTitleDisplayMode = .never
        navigationController?.pushViewController(vc, animated: true)
    }
  • 전달받은 selectionHandler 함수를 통해 플레이리스트 정보 사용 가능
  • selectionHandler 사용 후 곧바로 디스미스
public func addTrackToPlaylist(track: AudioTrack, playlist: Playlist, completionHandler: @escaping (Bool)->()) {
        createRequest(with: URL(string: Constants.baseAPIURL + "/playlists/\(playlist.id)/tracks"), type: .POST) { request in
            var request = request
            let json = ["uris" : ["spotify:track:\(track.id)"]]
            request.httpBody = try? JSONSerialization.data(withJSONObject: json, options: .fragmentsAllowed)
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
            URLSession.shared.dataTask(with: request) { data, response, error in
                guard
                    let data = data,
                    error == nil else {
                    completionHandler(false)
                    return
                }
                do {
                    let result = try JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed)
                    if let response = result as? [String : Any], response["snapshot_id"] as? String != nil {
                        print(response)
                        completionHandler(true)
                    } else {
                        completionHandler(false)
                    }
                } catch {
                    completionHandler(false)
                    print(error.localizedDescription)
                }
            }
            .resume()
        }
    }
  • 트랙, 플레이리스트 정보를 통해 해당 플레이리스트에 트랙 정보 추가
  • 컴플리션 핸들러를 통한 성공 여부 전달

구현 화면

profile
JUST DO IT

0개의 댓글