From de4259a95b3a36c23f3f97b30f1a485707d4ccd0 Mon Sep 17 00:00:00 2001 From: chopmozzi <44396392+chopmozzi@users.noreply.github.com> Date: Mon, 11 Dec 2023 00:24:34 +0900 Subject: [PATCH 1/3] =?UTF-8?q?:sparkles:=20=ED=99=88=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=95=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 7713bff390cf9a360c97967ef7e3bf458491dc66) --- .../Scenes/Playback/PlaybackInteractor.swift | 21 ++++++++++++++++ .../Scenes/Playback/PlaybackPresenter.swift | 6 +++++ .../Playback/PlaybackViewController.swift | 15 +++++++++++ .../Scenes/Playback/PlaybackWorker.swift | 16 +++++++++++- .../Workers/Mocks/MockPlaybackWorker.swift | 25 +++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift b/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift index b662bf7..3f4fc6b 100644 --- a/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift +++ b/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift @@ -29,6 +29,8 @@ protocol PlaybackBusinessLogic { func resumeVideo() func moveToProfile(with request: PlaybackModels.MoveToRelativeView.Request) func moveToTagPlay(with request: PlaybackModels.MoveToRelativeView.Request) + @discardableResult + func fetchPosts() -> Task } protocol PlaybackDataStore: AnyObject { @@ -67,6 +69,8 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { var selectedTag: String? + private var isFetchReqeust: Bool = false + // MARK: - UseCase Load Video List func displayVideoList() -> Task { @@ -289,4 +293,21 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { self.selectedTag = selectedTag presenter?.presentTagPlay() } + + func fetchPosts() -> Task { + Task { + if !isFetchReqeust { + isFetchReqeust = true + guard let posts = await worker?.fetchHomePosts() else { return false } + let videos: [Models.PlaybackVideo] = await transPostToVideo(posts) + let response: Models.LoadPlaybackVideoList.Response = Models.LoadPlaybackVideoList.Response(videos: videos) + await MainActor.run { + presenter?.presentLoadFetchVideos(with: response) + isFetchReqeust = false + } + return true + } + return false + } + } } diff --git a/iOS/Layover/Layover/Scenes/Playback/PlaybackPresenter.swift b/iOS/Layover/Layover/Scenes/Playback/PlaybackPresenter.swift index 8ea8303..75ff4ba 100644 --- a/iOS/Layover/Layover/Scenes/Playback/PlaybackPresenter.swift +++ b/iOS/Layover/Layover/Scenes/Playback/PlaybackPresenter.swift @@ -10,6 +10,7 @@ import Foundation protocol PlaybackPresentationLogic { func presentVideoList(with response: PlaybackModels.LoadPlaybackVideoList.Response) + func presentLoadFetchVideos(with response: PlaybackModels.LoadPlaybackVideoList.Response) func presentSetCellIfInfinite(with response: PlaybackModels.SetInitialPlaybackCell.Response) func presentMoveCellNext(with response: PlaybackModels.DisplayPlaybackVideo.Response) func presentSetInitialPlaybackCell(with response: PlaybackModels.SetInitialPlaybackCell.Response) @@ -42,6 +43,11 @@ final class PlaybackPresenter: PlaybackPresentationLogic { viewController?.displayVideoList(viewModel: viewModel) } + func presentLoadFetchVideos(with response: PlaybackModels.LoadPlaybackVideoList.Response) { + let viewModel: Models.LoadPlaybackVideoList.ViewModel = Models.LoadPlaybackVideoList.ViewModel(videos: response.videos) + viewController?.loadFetchVideos(viewModel: viewModel) + } + func presentSetCellIfInfinite(with response: PlaybackModels.SetInitialPlaybackCell.Response) { viewController?.displayMoveCellIfinfinite(viewModel: Models.SetInitialPlaybackCell.ViewModel(indexPathRow: response.indexPathRow)) } diff --git a/iOS/Layover/Layover/Scenes/Playback/PlaybackViewController.swift b/iOS/Layover/Layover/Scenes/Playback/PlaybackViewController.swift index 6206328..6416113 100644 --- a/iOS/Layover/Layover/Scenes/Playback/PlaybackViewController.swift +++ b/iOS/Layover/Layover/Scenes/Playback/PlaybackViewController.swift @@ -18,6 +18,7 @@ protocol PlaybackViewControllerDelegate: AnyObject { protocol PlaybackDisplayLogic: AnyObject { func displayVideoList(viewModel: PlaybackModels.LoadPlaybackVideoList.ViewModel) + func loadFetchVideos(viewModel: PlaybackModels.LoadPlaybackVideoList.ViewModel) func displayMoveCellIfinfinite(viewModel: PlaybackModels.SetInitialPlaybackCell.ViewModel) func stopPrevPlayerAndPlayCurPlayer(viewModel: PlaybackModels.DisplayPlaybackVideo.ViewModel) func setInitialPlaybackCell(viewModel: PlaybackModels.SetInitialPlaybackCell.ViewModel) @@ -188,6 +189,12 @@ extension PlaybackViewController: PlaybackDisplayLogic { dataSource?.apply(snapshot, animatingDifferences: false) } + func loadFetchVideos(viewModel: PlaybackModels.LoadPlaybackVideoList.ViewModel) { + guard var currentSnapshot = dataSource?.snapshot() else { return } + currentSnapshot.appendItems(viewModel.videos) + dataSource?.apply(currentSnapshot, animatingDifferences: true) + } + func displayMoveCellIfinfinite(viewModel: Models.SetInitialPlaybackCell.ViewModel) { playbackCollectionView.setContentOffset(.init(x: playbackCollectionView.contentOffset.x, y: playbackCollectionView.bounds.height * CGFloat(viewModel.indexPathRow)), animated: false) } @@ -334,6 +341,14 @@ extension PlaybackViewController: UICollectionViewDelegate { interactor?.playTeleportVideo(with: request) interactor?.careVideoLoading(with: request) } + + func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) { + let currentOffset = scrollView.contentOffset.y + let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height + if maximumOffset < currentOffset { + interactor?.fetchPosts() + } + } } extension PlaybackViewController: PlaybackViewControllerDelegate { diff --git a/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift b/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift index 456f90c..8d51f0d 100644 --- a/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift +++ b/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift @@ -16,6 +16,7 @@ protocol PlaybackWorkerProtocol { func makeInfiniteScroll(posts: [Post]) -> [Post] func transLocation(latitude: Double, longitude: Double) async -> String? func fetchImageData(with url: URL?) async -> Data? + func fetchHomePosts() async -> [Post]? } final class PlaybackWorker: PlaybackWorkerProtocol { @@ -26,12 +27,14 @@ final class PlaybackWorker: PlaybackWorkerProtocol { private let provider: ProviderType private let defaultPostManagerEndPointFactory: PostManagerEndPointFactory + private let defaultPostEndPointFactory: PostEndPointFactory // MARK: - Methods - init(provider: ProviderType = Provider(), defaultPostManagerEndPointFactory: PostManagerEndPointFactory = DefaultPostManagerEndPointFactory()) { + init(provider: ProviderType = Provider(), defaultPostManagerEndPointFactory: PostManagerEndPointFactory = DefaultPostManagerEndPointFactory(), defaultPostEndPointFactory: PostEndPointFactory = DefaultPostEndPointFactory()) { self.provider = provider self.defaultPostManagerEndPointFactory = defaultPostManagerEndPointFactory + self.defaultPostEndPointFactory = defaultPostEndPointFactory } func makeInfiniteScroll(posts: [Post]) -> [Post] { @@ -78,4 +81,15 @@ final class PlaybackWorker: PlaybackWorkerProtocol { return nil } } + + func fetchHomePosts() async -> [Post]? { + let endPoint = defaultPostEndPointFactory.makeHomePostListEndPoint() + do { + let response = try await provider.request(with: endPoint) + return response.data?.map { $0.toDomain() } + } catch { + os_log(.error, log: .default, "Failed to fetch posts: %@", error.localizedDescription) + return nil + } + } } diff --git a/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift b/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift index ec23402..598030a 100644 --- a/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift +++ b/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift @@ -100,4 +100,29 @@ final class MockPlaybackWorker: PlaybackWorkerProtocol { return nil } } + + func fetchHomePosts() async -> [Post]? { + guard let fileLocation = Bundle.main.url(forResource: "PostList", + withExtension: "json") else { return nil } + + do { + let mockData = try Data(contentsOf: fileLocation) + MockURLProtocol.requestHandler = { request in + let response = HTTPURLResponse(url: request.url!, + statusCode: 200, + httpVersion: nil, + headerFields: nil) + return (response, mockData, nil) + } + let endPoint: EndPoint = EndPoint>(path: "/board/home", + method: .GET) + let response = try await provider.request(with: endPoint) + guard let data = response.data else { return nil } + return data.map { $0.toDomain() } + } catch { + os_log(.error, log: .data, "%@", error.localizedDescription) + return nil + } + } + } From 94f8efcb8bf03b5604bf81270283bd727ea73370 Mon Sep 17 00:00:00 2001 From: chopmozzi <44396392+chopmozzi@users.noreply.github.com> Date: Mon, 11 Dec 2023 01:23:04 +0900 Subject: [PATCH 2/3] =?UTF-8?q?:sparkles:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=95=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit be87bc1c1f241d8c178565d0f7d0c18f2837ee73) --- .../Layover/Scenes/Map/MapRouter.swift | 2 +- .../Scenes/Playback/PlaybackInteractor.swift | 65 +++++++++++-------- .../Scenes/Playback/PlaybackModels.swift | 4 +- .../Scenes/Playback/PlaybackWorker.swift | 23 ++++++- .../Scenes/Profile/ProfileRouter.swift | 2 +- .../Workers/Mocks/MockPlaybackWorker.swift | 25 +++++++ 6 files changed, 90 insertions(+), 31 deletions(-) diff --git a/iOS/Layover/Layover/Scenes/Map/MapRouter.swift b/iOS/Layover/Layover/Scenes/Map/MapRouter.swift index 861c5a3..52538ac 100644 --- a/iOS/Layover/Layover/Scenes/Map/MapRouter.swift +++ b/iOS/Layover/Layover/Scenes/Map/MapRouter.swift @@ -50,6 +50,6 @@ final class MapRouter: MapRoutingLogic, MapDataPassing { private func passDataToPlayback(source: MapDataStore, destination: inout PlaybackDataStore) { destination.posts = source.posts destination.index = source.postPlayStartIndex - destination.parentView = .other + destination.parentView = .map } } diff --git a/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift b/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift index 3f4fc6b..fc6ab6a 100644 --- a/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift +++ b/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift @@ -71,6 +71,8 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { private var isFetchReqeust: Bool = false + private var currentPage: Int = 1 + // MARK: - UseCase Load Video List func displayVideoList() -> Task { @@ -78,7 +80,7 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { guard let parentView: Models.ParentView, var posts: [Post], let worker: PlaybackWorkerProtocol else { return false } - if parentView == .other { + if parentView == .map { posts = worker.makeInfiniteScroll(posts: posts) self.posts = posts } @@ -95,24 +97,17 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { guard let parentView, let index else { return } - switch parentView { - case .home, .myProfile: - presenter?.presentMoveInitialPlaybackCell(with: Models.SetInitialPlaybackCell.Response(indexPathRow: index)) - case .other: - presenter?.presentSetCellIfInfinite(with: Models.SetInitialPlaybackCell.Response(indexPathRow: index + 1)) - } + let willMoveIndex: Int + willMoveIndex = parentView == .map ? index + 1 : index + presenter?.presentMoveInitialPlaybackCell(with: Models.SetInitialPlaybackCell.Response(indexPathRow: willMoveIndex)) } func setInitialPlaybackCell() { guard let parentView, let index else { return } - let response: Models.SetInitialPlaybackCell.Response - switch parentView { - case .home, .myProfile: - response = Models.SetInitialPlaybackCell.Response(indexPathRow: index) - case .other: - response = Models.SetInitialPlaybackCell.Response(indexPathRow: index + 1) - } + let willMoveIndex: Int + willMoveIndex = parentView == .map ? index + 1 : index + let response: Models.SetInitialPlaybackCell.Response = Models.SetInitialPlaybackCell.Response(indexPathRow: willMoveIndex) presenter?.presentSetInitialPlaybackCell(with: response) } @@ -133,8 +128,8 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { isTeleport = false return } - // Home이 아닌 다른 뷰에서 왔을 경우(로드한 목록 무한 반복) - if parentView == .other { + // map에서 왔을 경우(로드한 목록 무한 반복) + if parentView == .map { if request.indexPathRow == (posts.count - 1) { response = Models.DisplayPlaybackVideo.Response(indexPathRow: 1, previousCell: previousCell, currentCell: nil) } else if request.indexPathRow == 0 { @@ -150,7 +145,7 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { presenter?.presentTeleportCell(with: response) return } - // Home이면 다음 셀로 이동(추가적인 비디오 로드) + // map이 아니면 다음 셀로 이동(추가적인 비디오 로드) isTeleport = false response = Models.DisplayPlaybackVideo.Response(previousCell: previousCell, currentCell: request.currentCell) previousCell = request.currentCell @@ -209,13 +204,9 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { func configurePlaybackCell() { guard let posts, let parentView else { return } - let response: Models.ConfigurePlaybackCell.Response - switch parentView { - case .home, .myProfile: - response = Models.ConfigurePlaybackCell.Response(teleportIndex: nil) - case .other: - response = Models.ConfigurePlaybackCell.Response(teleportIndex: posts.count + 1) - } + let willMoveTeleportIndex: Int? + willMoveTeleportIndex = parentView == .map ? posts.count + 1 : nil + let response: Models.ConfigurePlaybackCell.Response = Models.ConfigurePlaybackCell.Response(teleportIndex: willMoveTeleportIndex) presenter?.presentConfigureCell(with: response) } @@ -296,10 +287,32 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { func fetchPosts() -> Task { Task { + guard let posts else { return false } + let page: Int = posts.count / 15 + 1 + if page == currentPage { + return false + } + currentPage = page if !isFetchReqeust { isFetchReqeust = true - guard let posts = await worker?.fetchHomePosts() else { return false } - let videos: [Models.PlaybackVideo] = await transPostToVideo(posts) + var newPosts: [Post]? + switch parentView { + case .home: + newPosts = await worker?.fetchHomePosts() + case .map: + return false + case .myProfile, .otherProfile: + newPosts = await worker?.fetchProfilePosts(profileID: memberID, page: page) + case .tag: +// guard let selectedTag else { return false } +// newPosts = await worker?.fetchTagPosts(selectedTag: selectedTag, page: page) + return false + default: + return false + } + guard let newPosts else { return false } + self.posts?.append(contentsOf: newPosts) + let videos: [Models.PlaybackVideo] = await transPostToVideo(newPosts) let response: Models.LoadPlaybackVideoList.Response = Models.LoadPlaybackVideoList.Response(videos: videos) await MainActor.run { presenter?.presentLoadFetchVideos(with: response) diff --git a/iOS/Layover/Layover/Scenes/Playback/PlaybackModels.swift b/iOS/Layover/Layover/Scenes/Playback/PlaybackModels.swift index 5f7686f..f53b77d 100644 --- a/iOS/Layover/Layover/Scenes/Playback/PlaybackModels.swift +++ b/iOS/Layover/Layover/Scenes/Playback/PlaybackModels.swift @@ -18,7 +18,9 @@ enum PlaybackModels { enum ParentView { case home case myProfile - case other + case otherProfile + case tag + case map } struct DisplayedPost: Hashable { diff --git a/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift b/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift index 8d51f0d..7932d77 100644 --- a/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift +++ b/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift @@ -17,6 +17,8 @@ protocol PlaybackWorkerProtocol { func transLocation(latitude: Double, longitude: Double) async -> String? func fetchImageData(with url: URL?) async -> Data? func fetchHomePosts() async -> [Post]? + func fetchProfilePosts(profileID: Int?, page: Int) async -> [Post]? +// func fetchTagPosts(selectedTag: String, page: Int) async -> [Post]? } final class PlaybackWorker: PlaybackWorkerProtocol { @@ -28,13 +30,15 @@ final class PlaybackWorker: PlaybackWorkerProtocol { private let provider: ProviderType private let defaultPostManagerEndPointFactory: PostManagerEndPointFactory private let defaultPostEndPointFactory: PostEndPointFactory + private let defaultUserEndPointFactory: UserEndPointFactory // MARK: - Methods - init(provider: ProviderType = Provider(), defaultPostManagerEndPointFactory: PostManagerEndPointFactory = DefaultPostManagerEndPointFactory(), defaultPostEndPointFactory: PostEndPointFactory = DefaultPostEndPointFactory()) { + init(provider: ProviderType = Provider(), defaultPostManagerEndPointFactory: PostManagerEndPointFactory = DefaultPostManagerEndPointFactory(), defaultPostEndPointFactory: PostEndPointFactory = DefaultPostEndPointFactory(), defaultUserEndPointFactory: UserEndPointFactory = DefaultUserEndPointFactory()) { self.provider = provider self.defaultPostManagerEndPointFactory = defaultPostManagerEndPointFactory self.defaultPostEndPointFactory = defaultPostEndPointFactory + self.defaultUserEndPointFactory = defaultUserEndPointFactory } func makeInfiniteScroll(posts: [Post]) -> [Post] { @@ -88,8 +92,23 @@ final class PlaybackWorker: PlaybackWorkerProtocol { let response = try await provider.request(with: endPoint) return response.data?.map { $0.toDomain() } } catch { - os_log(.error, log: .default, "Failed to fetch posts: %@", error.localizedDescription) + os_log(.error, log: .data, "Failed to fetch posts: %@", error.localizedDescription) return nil } } + + func fetchProfilePosts(profileID: Int?, page: Int) async -> [Post]? { + let endPoint = defaultUserEndPointFactory.makeUserPostsEndPoint(at: page, of: profileID) + do { + let response = try await provider.request(with: endPoint) + return response.data?.map { $0.toDomain() } + } catch { + os_log(.error, log: .data, "Failed to fetch posts: %@", error.localizedDescription) + return nil + } + } + +// func fetchTagPosts(selectedTag: String, page: Int) async -> [Post]? { +// let endPoint = defaultPostEndPointFactory.makeTagSearchPostListEndPoint(by: <#T##String#>) +// } } diff --git a/iOS/Layover/Layover/Scenes/Profile/ProfileRouter.swift b/iOS/Layover/Layover/Scenes/Profile/ProfileRouter.swift index 3dacd61..f81ba6d 100644 --- a/iOS/Layover/Layover/Scenes/Profile/ProfileRouter.swift +++ b/iOS/Layover/Layover/Scenes/Profile/ProfileRouter.swift @@ -64,6 +64,6 @@ final class ProfileRouter: ProfileRoutingLogic, ProfileDataPassing { private func passDataToPlayback(source: ProfileDataStore, destination: inout PlaybackDataStore) { destination.posts = source.posts destination.index = source.playbackStartIndex - destination.parentView = .myProfile + destination.parentView = source.profileId == nil ? .myProfile : .otherProfile } } diff --git a/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift b/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift index 598030a..525d4ed 100644 --- a/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift +++ b/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift @@ -125,4 +125,29 @@ final class MockPlaybackWorker: PlaybackWorkerProtocol { } } + func fetchProfilePosts(profileID: Int?, page: Int) async -> [Post]? { + guard let fileLocation = Bundle.main.url(forResource: "PostList", + withExtension: "json") else { return nil } + + do { + let mockData = try Data(contentsOf: fileLocation) + MockURLProtocol.requestHandler = { request in + let response = HTTPURLResponse(url: request.url!, + statusCode: 200, + httpVersion: nil, + headerFields: nil) + return (response, mockData, nil) + } + let endPoint: EndPoint = EndPoint>(path: "/board/profile", + method: .GET) + let response = try await provider.request(with: endPoint) + guard let data = response.data else { return nil } + return data.map { $0.toDomain() } + } catch { + os_log(.error, log: .data, "%@", error.localizedDescription) + return nil + } + + } + } From c82d0afe6ca768dc40ab8ec65abd8b51bdbde499 Mon Sep 17 00:00:00 2001 From: chopmozzi <44396392+chopmozzi@users.noreply.github.com> Date: Mon, 11 Dec 2023 02:21:52 +0900 Subject: [PATCH 3/3] =?UTF-8?q?:sparkles:=20=ED=83=9C=EA=B7=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=95=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit bd0985c365864a4e784b46d93398330304b7ac46) --- .../Scenes/Playback/PlaybackInteractor.swift | 20 +++++----- .../Scenes/Playback/PlaybackWorker.swift | 15 +++++-- .../TagPlayList/TagPlayListRouter.swift | 2 +- .../Workers/Mocks/MockPlaybackWorker.swift | 40 +++++++++++++++---- 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift b/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift index fc6ab6a..6b6d518 100644 --- a/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift +++ b/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift @@ -287,14 +287,17 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { func fetchPosts() -> Task { Task { - guard let posts else { return false } - let page: Int = posts.count / 15 + 1 - if page == currentPage { - return false - } - currentPage = page if !isFetchReqeust { isFetchReqeust = true + var page: Int = 0 + if parentView != .home { + guard let posts else { return false } + page = posts.count / 15 + 1 + if page == currentPage { + return false + } + } + currentPage = page var newPosts: [Post]? switch parentView { case .home: @@ -304,9 +307,8 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { case .myProfile, .otherProfile: newPosts = await worker?.fetchProfilePosts(profileID: memberID, page: page) case .tag: -// guard let selectedTag else { return false } -// newPosts = await worker?.fetchTagPosts(selectedTag: selectedTag, page: page) - return false + guard let selectedTag else { return false } + newPosts = await worker?.fetchTagPosts(selectedTag: selectedTag, page: page) default: return false } diff --git a/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift b/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift index 7932d77..da91dba 100644 --- a/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift +++ b/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift @@ -18,7 +18,7 @@ protocol PlaybackWorkerProtocol { func fetchImageData(with url: URL?) async -> Data? func fetchHomePosts() async -> [Post]? func fetchProfilePosts(profileID: Int?, page: Int) async -> [Post]? -// func fetchTagPosts(selectedTag: String, page: Int) async -> [Post]? + func fetchTagPosts(selectedTag: String, page: Int) async -> [Post]? } final class PlaybackWorker: PlaybackWorkerProtocol { @@ -108,7 +108,14 @@ final class PlaybackWorker: PlaybackWorkerProtocol { } } -// func fetchTagPosts(selectedTag: String, page: Int) async -> [Post]? { -// let endPoint = defaultPostEndPointFactory.makeTagSearchPostListEndPoint(by: <#T##String#>) -// } + func fetchTagPosts(selectedTag: String, page: Int) async -> [Post]? { + let endPoint = defaultPostEndPointFactory.makeTagSearchPostListEndPoint(of: selectedTag, at: page) + do { + let response = try await provider.request(with: endPoint) + return response.data?.map { $0.toDomain() } + } catch { + os_log(.error, log: .data, "Failed to fetch posts: %@", error.localizedDescription) + return nil + } + } } diff --git a/iOS/Layover/Layover/Scenes/TagPlayList/TagPlayListRouter.swift b/iOS/Layover/Layover/Scenes/TagPlayList/TagPlayListRouter.swift index 797a48f..ad40750 100644 --- a/iOS/Layover/Layover/Scenes/TagPlayList/TagPlayListRouter.swift +++ b/iOS/Layover/Layover/Scenes/TagPlayList/TagPlayListRouter.swift @@ -33,7 +33,7 @@ final class TagPlayListRouter: TagPlayListRoutingLogic, TagPlayListDataPassing { } private func passDataToPlayback(source: TagPlayListDataStore, destination: inout PlaybackDataStore) { - destination.parentView = .other + destination.parentView = .tag destination.index = source.postPlayStartIndex destination.posts = source.posts } diff --git a/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift b/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift index 525d4ed..ca84a80 100644 --- a/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift +++ b/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift @@ -126,9 +126,8 @@ final class MockPlaybackWorker: PlaybackWorkerProtocol { } func fetchProfilePosts(profileID: Int?, page: Int) async -> [Post]? { - guard let fileLocation = Bundle.main.url(forResource: "PostList", - withExtension: "json") else { return nil } - + let resourceFileName = switch page { case 1: "PostList" case 2: "PostListMore" default: "PostListEnd" } + guard let fileLocation = Bundle.main.url(forResource: resourceFileName, withExtension: "json") else { return nil } do { let mockData = try Data(contentsOf: fileLocation) MockURLProtocol.requestHandler = { request in @@ -138,16 +137,43 @@ final class MockPlaybackWorker: PlaybackWorkerProtocol { headerFields: nil) return (response, mockData, nil) } - let endPoint: EndPoint = EndPoint>(path: "/board/profile", - method: .GET) + let endPoint = EndPoint>(path: "/member/posts", + method: .GET, + queryParameters: ["page": page]) let response = try await provider.request(with: endPoint) - guard let data = response.data else { return nil } - return data.map { $0.toDomain() } + return response.data?.map { $0.toDomain() } } catch { os_log(.error, log: .data, "%@", error.localizedDescription) return nil } + } + func fetchTagPosts(selectedTag: String, page: Int) async -> [Post]? { + let resourceFileName = switch page { case 1: "PostList" case 2: "PostListMore" default: "PostListEnd" } + guard let fileLocation = Bundle.main.url(forResource: resourceFileName, withExtension: "json") else { + return nil + } + + do { + let mockData = try? Data(contentsOf: fileLocation) + MockURLProtocol.requestHandler = { request in + let response = HTTPURLResponse(url: request.url!, + statusCode: 200, + httpVersion: nil, + headerFields: nil) + return (response, mockData, nil) + } + + let endPoint = EndPoint>(path: "/board/tag", + method: .GET, + queryParameters: ["tag": selectedTag]) + + let response = try await provider.request(with: endPoint) + return response.data?.map { $0.toDomain() } + } catch { + os_log(.error, log: .data, "%@", error.localizedDescription) + return nil + } } }