Skip to content

Commit

Permalink
[feat] 플레이리스트 옮기기 -> 음악 선택 후 옮기기 버튼 클릭 기능 (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jaewift committed Nov 24, 2024
1 parent a06924f commit fc50417
Show file tree
Hide file tree
Showing 14 changed files with 749 additions and 915 deletions.
4 changes: 4 additions & 0 deletions PLUV.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
C7EB31622CD4ED5700DA439A /* ValidationNotFoundTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7EB31612CD4ED5700DA439A /* ValidationNotFoundTableViewCell.swift */; };
C7EEA4F22CC3A59F00FBAA4D /* RecentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7EEA4F12CC3A59F00FBAA4D /* RecentCollectionViewCell.swift */; };
C7EEA4F42CC3A5AE00FBAA4D /* SaveCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7EEA4F32CC3A5AE00FBAA4D /* SaveCollectionViewCell.swift */; };
C7F7AD5D2CF345170082FDB5 /* SelectMusicProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F7AD5C2CF345170082FDB5 /* SelectMusicProtocol.swift */; };
C7FA72812CDF1B3A00EB3D91 /* SelectMeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7FA72802CDF1B3A00EB3D91 /* SelectMeViewModel.swift */; };
C7FA72832CDF1B4600EB3D91 /* SelectSaveViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7FA72822CDF1B4600EB3D91 /* SelectSaveViewModel.swift */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -259,6 +260,7 @@
C7EB31612CD4ED5700DA439A /* ValidationNotFoundTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidationNotFoundTableViewCell.swift; sourceTree = "<group>"; };
C7EEA4F12CC3A59F00FBAA4D /* RecentCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentCollectionViewCell.swift; sourceTree = "<group>"; };
C7EEA4F32CC3A5AE00FBAA4D /* SaveCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveCollectionViewCell.swift; sourceTree = "<group>"; };
C7F7AD5C2CF345170082FDB5 /* SelectMusicProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectMusicProtocol.swift; sourceTree = "<group>"; };
C7FA72802CDF1B3A00EB3D91 /* SelectMeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectMeViewModel.swift; sourceTree = "<group>"; };
C7FA72822CDF1B4600EB3D91 /* SelectSaveViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectSaveViewModel.swift; sourceTree = "<group>"; };
CDAD2C02EE2D55B201611407 /* Pods_PLUVTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PLUVTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -327,6 +329,7 @@
C78221A52CE3B42900568DFF /* SelectMePlaylistViewModel.swift */,
C78221A72CE3B43900568DFF /* SelectSavePlaylistViewModel.swift */,
6889F5152C6CE56F001F5FC2 /* SelectMusicViewController.swift */,
C7F7AD5C2CF345170082FDB5 /* SelectMusicProtocol.swift */,
6889F51D2C6D52B7001F5FC2 /* SelectMusicViewModel.swift */,
C7FA72802CDF1B3A00EB3D91 /* SelectMeViewModel.swift */,
C7FA72822CDF1B4600EB3D91 /* SelectSaveViewModel.swift */,
Expand Down Expand Up @@ -943,6 +946,7 @@
68E312252CBC024D00243658 /* FeedDetailTableViewCell.swift in Sources */,
68DC4C772C6B6E9E006D8E97 /* SelectPlaylistCollectionViewCell.swift in Sources */,
68F6FAB22C4A9CCA001128FF /* WhiteButton.swift in Sources */,
C7F7AD5D2CF345170082FDB5 /* SelectMusicProtocol.swift in Sources */,
C7C806FE2CCCD7F600245FEA /* RecentTabViewController.swift in Sources */,
68830FAF2C8264CA00995785 /* FeedViewModel.swift in Sources */,
68EE372D2CB0749E0077632B /* FeedInfo.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions PLUV/Component/LoadingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ final class LoadingView: UIView {
label.numberOfLines = 2
label.textAlignment = .center
label.textColor = .gray800
label.font = .systemFont(ofSize: 20, weight: .medium)
}
let loadingContainerView = UIView()
let loadingBar = UIView()
Expand Down
5 changes: 1 addition & 4 deletions PLUV/Component/SaveMoveView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ final class SaveMoveView: UIView {
if isOriginalColor {
saveButton.setImage(UIImage(named: "savebutton_icon2"), for: .normal)
feedDelegate?.setFeedSaveAPI()
saveDelegate?.setFeedSaveAPI()
} else {
saveButton.setImage(UIImage(named: "savebutton_icon"), for: .normal)
feedDelegate?.deleteFeedSaveAPI()
Expand All @@ -98,8 +99,4 @@ final class SaveMoveView: UIView {
saveButton.setImage(UIImage(named: imageName), for: .normal)
isOriginalColor = isSaved
}

func updateSaveButton() {
saveButton.isEnabled = false
}
}
10 changes: 6 additions & 4 deletions PLUV/Component/ValidationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ final class ValidationView: UIView {
var noSongImageView = UIImageView().then {
$0.contentMode = .scaleAspectFill
}
var titleLabel = UILabel().then {
$0.textColor = .gray800
$0.font = .systemFont(ofSize: 20, weight: .medium)
}
var titleLabel = UILabel().then {
$0.numberOfLines = 2
$0.textAlignment = .center
$0.textColor = .gray800
$0.font = .systemFont(ofSize: 20, weight: .medium)
}

init(title: String, image: String) {
super.init(frame: .zero)
Expand Down
6 changes: 3 additions & 3 deletions PLUV/Feed/FeedDetailTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ final class FeedDetailTableViewCell: UITableViewCell {
$0.font = .systemFont(ofSize: 15)
}
private let thumbnailImageView = UIImageView().then {
$0.contentMode = .scaleAspectFit
$0.layer.cornerRadius = 5
$0.layer.borderColor = UIColor.gray300.cgColor
$0.layer.borderWidth = 0.5
Expand All @@ -29,7 +28,7 @@ final class FeedDetailTableViewCell: UITableViewCell {
$0.font = .systemFont(ofSize: 15) /// g, y, p 같은 문자 이슈로 1point 줄임
}
private let singerLabel = UILabel().then {
$0.textColor = .gray500
$0.textColor = .gray600
$0.font = .systemFont(ofSize: 13) /// g, y, p 같은 문자 이슈로 1point 줄임
}

Expand All @@ -50,7 +49,7 @@ final class FeedDetailTableViewCell: UITableViewCell {
numberLabel.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(20)
make.centerY.equalToSuperview()
make.width.equalTo(16)
make.width.equalTo(20)
make.height.equalTo(14)
}

Expand All @@ -65,6 +64,7 @@ final class FeedDetailTableViewCell: UITableViewCell {
self.contentView.addSubview(songTitleLabel)
songTitleLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(15)
make.trailing.equalToSuperview().inset(24)
make.leading.equalTo(thumbnailImageView.snp.trailing).offset(12)
make.height.equalTo(16)
}
Expand Down
22 changes: 9 additions & 13 deletions PLUV/Feed/FeedDetailViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ class FeedDetailViewController: UIViewController, SaveMoveViewFeedDelegate {
setSaveAPI()
}

// override func viewDidLayoutSubviews() {
// super.viewDidLayoutSubviews()
// setTableViewHeight() /// 레이아웃이 갱신될 때마다 테이블 뷰 높이 갱신
// }
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
setTableViewHeight()
}

private func setUI() {
self.view.backgroundColor = .white
Expand Down Expand Up @@ -173,11 +173,13 @@ class FeedDetailViewController: UIViewController, SaveMoveViewFeedDelegate {
}

private func setTableViewHeight() {
feedDetailTableView.layoutIfNeeded()

let contentHeight = feedDetailTableView.contentSize.height
feedDetailTableViewHeightConstraint?.update(offset: contentHeight + 300)
feedDetailTableViewHeightConstraint?.update(offset: contentHeight + 100)

/// 이미지 높이 + 테이블 뷰 높이를 합산하여 스크롤뷰의 contentSize 설정
let totalHeight = feedDetailImageView.frame.height + feedDetailTitleView.frame.height + 10 + contentHeight + 101
let totalHeight = navigationbarView.frame.height + feedDetailImageView.frame.height + feedDetailTitleView.frame.height + contentHeight
scrollView.contentSize = CGSize(width: view.frame.width, height: totalHeight)
scrollView.layoutIfNeeded()
}
Expand Down Expand Up @@ -206,6 +208,7 @@ class FeedDetailViewController: UIViewController, SaveMoveViewFeedDelegate {
case 200:
self.viewModel.selectFeedMusicItem.accept(response.data)
self.setData()
self.view.layoutIfNeeded()
default:
AlertController(message: response.msg).show()
}
Expand All @@ -223,13 +226,6 @@ class FeedDetailViewController: UIViewController, SaveMoveViewFeedDelegate {
cell.prepare(music: music, index: index)
}
.disposed(by: disposeBag)

/// 데이터 로드 후 레이아웃 강제 업데이트
DispatchQueue.main.async {
self.feedDetailTableView.reloadData()
self.feedDetailTableView.layoutIfNeeded()
self.setTableViewHeight()
}
}

func setFeedSaveAPI() {
Expand Down
129 changes: 6 additions & 123 deletions PLUV/Move/MovePlaylistViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class MovePlaylistViewController: UIViewController {
$0.font = .systemFont(ofSize: 18)
}
private var platformLabel = UILabel().then {
$0.textColor = .subBlue
$0.textColor = .gray800
$0.font = .systemFont(ofSize: 14)
$0.textAlignment = .center
}
Expand Down Expand Up @@ -90,7 +90,9 @@ class MovePlaylistViewController: UIViewController {

setUI()
setPlaylistData()
searchAPI()
Task {
await self.addSpotifyToApple(musicIdsArr: completeArr)
}

circleLoadingIndicator.isAnimating = true

Expand Down Expand Up @@ -238,125 +240,6 @@ class MovePlaylistViewController: UIViewController {
}
}

private func searchAPI() {
if let musicPlatform = sourcePlatform as? MusicPlatform, musicPlatform == .AppleMusic && destinationPlatform == .Spotify {
/// 권한이 부여된 경우에만 넘겨야함!!!
Task {
await self.searchAppleToSpotifyAPI(musics: self.viewModel.musicItems)
}
} else if let musicPlatform = sourcePlatform as? MusicPlatform, musicPlatform == .Spotify && destinationPlatform == .AppleMusic {
MPMediaLibrary.requestAuthorization { status in
switch status {
case .authorized:
/// 권한이 부여된 경우
print("Apple Music authorization granted")
Task {
await self.searchSpotifyToAppleAPI(musics: self.viewModel.musicItems)
}
default:
DispatchQueue.main.async {
AlertController(message: "미디어 권한을 허용해야 사용할 수 있어요") {
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
}.show()
}
}
}
}
}

/// 애플에 있는 것 스포티파이에서 검색
private func searchAppleToSpotifyAPI(musics: [Music]) async {
do {
let jsonData = try JSONEncoder().encode(musics)
let jsonString = String(data: jsonData, encoding: .utf8) ?? ""
let musicParams = jsonString.replacingOccurrences(of: "\\", with: "").replacingOccurrences(of: "artistNames", with: "artistName")

if let parameterJsonData = musicParams.data(using: .utf8) {
do {
if let parameterJsonArray = try JSONSerialization.jsonObject(with: parameterJsonData, options: []) as? [[String: Any]] {

let url = EndPoint.musicSpotifySearch.path
let params = ["destinationAccessToken" : TokenManager.shared.spotifyAccessToken,
"musics" : parameterJsonArray] as [String : Any]

APIService().post(of: APIResponse<[Search]>.self, url: url, parameters: params) { response in
switch response.code {
case 200:
var idArr: [String] = []
let searchArr: [Search] = response.data
for search in searchArr {
if search.isEqual == true {
idArr.append(search.destinationMusics.first!.id!)
} else {
idArr.append(search.destinationMusics.first!.id!)
}
}
print(response.data, "애플에 있는 것 스포티파이에서 검색")
self.addAppleToSpotify(musicIdsArr: idArr)
default:
AlertController(message: response.msg).show()
}
}
}
} catch {
print("JSON 변환 실패: \(error.localizedDescription)")
}
}
} catch {
print(error)
}
}

/// 스포티파이에 있는 것 애플에서 검색
private func searchSpotifyToAppleAPI(musics: [Music]) async {
do {
let developerToken = try await DefaultMusicTokenProvider.init().developerToken(options: .ignoreCache)
let userToken = try await MusicUserTokenProvider.init().userToken(for: developerToken, options: .ignoreCache)

let jsonData = try JSONEncoder().encode(musics)
let jsonString = String(data: jsonData, encoding: .utf8) ?? ""
let musicParams = jsonString.replacingOccurrences(of: "\\", with: "").replacingOccurrences(of: "artistNames", with: "artistName")

if let parameterJsonData = musicParams.data(using: .utf8) {
do {
if let parameterJsonArray = try JSONSerialization.jsonObject(with: parameterJsonData, options: []) as? [[String: Any]] {

let url = EndPoint.musicAppleSearch.path
let params = ["destinationAccessToken" : userToken,
"musics" : parameterJsonArray] as [String : Any]
print(params, "파람 확인")
APIService().post(of: APIResponse<[Search]>.self, url: url, parameters: params) { response in
switch response.code {
case 200:
var idArr: [String] = []
let searchArr: [Search] = response.data
for search in searchArr {
if search.isEqual == true {
idArr.append(search.destinationMusics.first!.id!)
} else {
if let id = search.destinationMusics.first?.id {
idArr.append(id)
}
}
}
print(response.data, "스포티파이에 있는 것 애플에서 검색")
Task {
await self.addSpotifyToApple(musicIdsArr: idArr)
}
default:
AlertController(message: response.msg).show()
}
}
}
} catch {
print("JSON 변환 실패: \(error.localizedDescription)")
}
}
} catch {
print(error)
}
}

/// 애플에 있는 것 스포티파이에 등록
private func addAppleToSpotify(musicIdsArr: [String]) {
let loginToken = UserDefaults.standard.string(forKey: APIService.shared.loginAccessTokenKey)!
Expand Down Expand Up @@ -399,12 +282,12 @@ class MovePlaylistViewController: UIViewController {

let url = EndPoint.musicAppleAdd.path
let params = [
"playListName": self.viewModel.playlistItem?.name ?? "",
"playListName": self.saveViewModel.saveItem?.title ?? "",
"destinationAccessToken": musicUserToken,
"musicIds": musicIdsArr,
"transferFailMusics": [
],
"thumbNailUrl": self.viewModel.playlistItem?.thumbnailURL ?? "",
"thumbNailUrl": self.saveViewModel.saveItem?.thumbNailURL ?? "",
"source": "spotify"
] as [String : Any]

Expand Down
3 changes: 2 additions & 1 deletion PLUV/Save/Cell/SaveSongsTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class SaveSongsTableViewCell: UITableViewCell {
indexLabel.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(20)
make.centerY.equalToSuperview()
make.width.equalTo(16)
make.width.equalTo(20)
make.height.equalTo(14)
}

Expand All @@ -62,6 +62,7 @@ class SaveSongsTableViewCell: UITableViewCell {
self.contentView.addSubview(nameLabel)
nameLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(15)
make.trailing.equalToSuperview().inset(24)
make.leading.equalTo(thumbnailImageView.snp.trailing).offset(12)
make.height.equalTo(16)
}
Expand Down
17 changes: 16 additions & 1 deletion PLUV/Save/SaveDetailViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import RxCocoa
import Alamofire

protocol SaveMoveViewSaveDelegate: AnyObject {
func setFeedSaveAPI()
func deleteFeedSaveAPI()
func transferFeedSave()
}
Expand Down Expand Up @@ -221,6 +222,21 @@ class SaveDetailViewController: UIViewController, SaveMoveViewSaveDelegate {
}
}

func setFeedSaveAPI() {
guard let id = self.viewModel.selectSaveItem?.id else { return }
let loginToken = UserDefaults.standard.string(forKey: APIService.shared.loginAccessTokenKey)!
let url = EndPoint.feedIdSave(String(id)).path

APIService().postWithAccessToken(of: APIResponse<String>.self, url: url, parameters: nil, AccessToken: loginToken) { response in
switch response.code {
case 200:
print("피드 저장이 정상적으로 처리되었습니다.")
default:
AlertController(message: response.msg).show()
}
}
}

func deleteFeedSaveAPI() {
guard let id = self.viewModel.selectSaveItem?.id else { return }
let loginToken = UserDefaults.standard.string(forKey: APIService.shared.loginAccessTokenKey)!
Expand All @@ -230,7 +246,6 @@ class SaveDetailViewController: UIViewController, SaveMoveViewSaveDelegate {
switch response.code {
case 200:
print("피드 삭제가 정상적으로 처리되었습니다.")
self.saveMoveView.updateSaveButton()
default:
AlertController(message: response.msg).show()
}
Expand Down
Loading

0 comments on commit fc50417

Please sign in to comment.