From d627eb23f80cbaacb35261ba3586fe1cfae01c1f Mon Sep 17 00:00:00 2001 From: thinkyside Date: Sun, 3 Nov 2024 16:04:31 +0900 Subject: [PATCH] =?UTF-8?q?[FIX/#177]=20PlatProcessing=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PLAT/PLAT/Component/PlatProgressView.swift | 6 +- PLAT/PLAT/Component/ToastMessage.swift | 29 ++- .../Register/SelectStreamAccountView.swift | 5 +- .../Presentaion/Register/SignUpOrInView.swift | 7 +- .../TrackAppend/TrackAppendSearchSheet.swift | 5 +- .../Presentaion/TrackFeed/TrackFeedView.swift | 212 +++++++++--------- 6 files changed, 132 insertions(+), 132 deletions(-) diff --git a/PLAT/PLAT/Component/PlatProgressView.swift b/PLAT/PLAT/Component/PlatProgressView.swift index b2792728..ec5b03d8 100644 --- a/PLAT/PLAT/Component/PlatProgressView.swift +++ b/PLAT/PLAT/Component/PlatProgressView.swift @@ -8,6 +8,9 @@ import SwiftUI struct PlatProgressView: View { + + let isLoading: Bool + var body: some View { ZStack { Rectangle() @@ -21,9 +24,10 @@ struct PlatProgressView: View { .tint(.primary) } .ignoresSafeArea() + .opacity(isLoading ? 1 : 0) } } #Preview { - PlatProgressView() + PlatProgressView(isLoading: true) } diff --git a/PLAT/PLAT/Component/ToastMessage.swift b/PLAT/PLAT/Component/ToastMessage.swift index fd2a37fd..b60305d6 100644 --- a/PLAT/PLAT/Component/ToastMessage.swift +++ b/PLAT/PLAT/Component/ToastMessage.swift @@ -15,20 +15,25 @@ struct ToastMessage: View { @Binding private(set) var isToastPresented: Bool var body: some View { - HStack(spacing: 18) { - Image(systemName: SystemImage.exclamationmark) - .resizable() - .frame(width: 24, height: 24) - .foregroundStyle(.platPurple) + VStack { + Spacer() - Text(message) - .foregroundStyle(.white) - .font(.Body.body1) + HStack(spacing: 18) { + Image(systemName: SystemImage.exclamationmark) + .resizable() + .frame(width: 24, height: 24) + .foregroundStyle(.platPurple) + + Text(message) + .foregroundStyle(.white) + .font(.Body.body1) + } + .padding(.horizontal, 24) + .padding(.vertical, 22) + .background(.platBlack) + .clipShape(RoundedRectangle(cornerRadius: 40)) } - .padding(.horizontal, 24) - .padding(.vertical, 22) - .background(.platBlack) - .clipShape(RoundedRectangle(cornerRadius: 40)) + .padding(.bottom, 30) .opacity(opacity) .onChange(of: isToastPresented) { _, flag in if flag { toggleToast() } diff --git a/PLAT/PLAT/Presentaion/Register/SelectStreamAccountView.swift b/PLAT/PLAT/Presentaion/Register/SelectStreamAccountView.swift index 94f38675..4c97ad59 100644 --- a/PLAT/PLAT/Presentaion/Register/SelectStreamAccountView.swift +++ b/PLAT/PLAT/Presentaion/Register/SelectStreamAccountView.swift @@ -87,10 +87,7 @@ struct SelectStreamAccountView: View { .navigationTitle("스트리밍 계정 선택하기") .navigationBarTitleDisplayMode(.inline) .navigationBarBackButtonHidden() - .overlay( - musicControlUseCase.state.isLoading - ? AnyView(PlatProgressView()) : AnyView(EmptyView()) - ) + .overlay(PlatProgressView(isLoading: musicControlUseCase.state.isLoading)) .alert("일시적인 오류로 계정 연결에 실패했습니다. 다시 시도해주세요.", isPresented: $isConnectFailedAlertPresented) { AlertActionButton(variant: .confim) } diff --git a/PLAT/PLAT/Presentaion/Register/SignUpOrInView.swift b/PLAT/PLAT/Presentaion/Register/SignUpOrInView.swift index 500ad289..7157c58d 100644 --- a/PLAT/PLAT/Presentaion/Register/SignUpOrInView.swift +++ b/PLAT/PLAT/Presentaion/Register/SignUpOrInView.swift @@ -19,7 +19,7 @@ struct SignUpOrInView: View { @State private var isLoginFailedAlertPresented = false var body: some View { - ZStack { + Group { if authUseCase.state.authType == .signUp { SignUpView( isLoading: $isLoading, @@ -31,11 +31,8 @@ struct SignUpOrInView: View { isLoginFailedAlertPresented: $isLoginFailedAlertPresented ) } - - if isLoading { - PlatProgressView() - } } + .overlay(PlatProgressView(isLoading: isLoading)) .tint(.white) .toolbarRole(.editor) .navigationBarTitleDisplayMode(.inline) diff --git a/PLAT/PLAT/Presentaion/TrackAppend/TrackAppendSearchSheet.swift b/PLAT/PLAT/Presentaion/TrackAppend/TrackAppendSearchSheet.swift index c63fd778..b354ca74 100644 --- a/PLAT/PLAT/Presentaion/TrackAppend/TrackAppendSearchSheet.swift +++ b/PLAT/PLAT/Presentaion/TrackAppend/TrackAppendSearchSheet.swift @@ -81,10 +81,7 @@ struct TrackAppendSearchSheet: View { } } } - .overlay( - PlatProgressView() - .opacity(isLoading ? 1 : 0) - ) + .overlay(PlatProgressView(isLoading: isLoading)) .onSubmit { recentSearchTermList.append(searchTerm) UserDefaults.standard.recentSearchTermList = recentSearchTermList diff --git a/PLAT/PLAT/Presentaion/TrackFeed/TrackFeedView.swift b/PLAT/PLAT/Presentaion/TrackFeed/TrackFeedView.swift index 971a7e9b..8d35354b 100644 --- a/PLAT/PLAT/Presentaion/TrackFeed/TrackFeedView.swift +++ b/PLAT/PLAT/Presentaion/TrackFeed/TrackFeedView.swift @@ -18,62 +18,6 @@ struct TrackFeedView: View { @State private var isLoading = false @State private var isNonePlaylistToastPresented = false - /// 트랙 리스트를 반환합니다. - private var trackList: [Track] { - trackUseCase.feedTrackList.filter { - let reportedTrackIdList = UserDefaults.standard.reportedTrackIdList - return !reportedTrackIdList.contains($0.id) - } - } - - /// Feed를 업데이트합니다. - private func updateFeed(from trackList: [Track]) async throws { - let fetchMusicListResult = await musicControlUseCase.fetchMusicList(from: trackList) - - switch fetchMusicListResult { - case .success(let musicList): - trackUseCase.updateFeedTrackListMusicInfo(from: musicList) - - case .failure(let error): - throw error - } - } - - /// MiniMusicPlayer를 탭합니다. - private func miniMusicPlayerTapped(with trackId: Int) { - Task { - let updateCurrentTrackResult = await trackUseCase.fetchCurrentTrack(from: trackId) - switch updateCurrentTrackResult { - case .success(let fetchTrack): - - let musicResult = await musicControlUseCase.fetchMusic(from: fetchTrack) - switch musicResult { - case .success(let music): - trackUseCase.updateCurrentTrackMusicInfo(from: music) - let currentTrack = trackUseCase.currentTrack - musicControlUseCase.updateCurrentTrack(to: currentTrack) - pathModel.presentFullScreenCover(.trackDetail) - - case .failure(let error): - // TODO: 에러 처리 - print(error) - } - - case .failure(let error): - // TODO: 에러 처리 - print(error) - } - } - } - - /// 다음 페이지를 Fetch합니다. - private func fetchNextPage() { - Task { - let trackList = await trackUseCase.paginationFeedTrackList() - try await updateFeed(from: trackList) - } - } - var body: some View { @Bindable var musicControlUseCase = musicControlUseCase ZStack { @@ -82,27 +26,11 @@ struct TrackFeedView: View { .padding(.leading, 20) .padding(.vertical, 8) - ScrollView { - LazyVStack { - ForEach(Array(trackList.enumerated()), id: \.offset) { index, track in - FeedRowView( - currentTrack: $musicControlUseCase.state.currentTrack, - isLoading: $isLoading, - isNonePlaylistToastPresented: $isNonePlaylistToastPresented, - track: track, - playlistId: "", - address: track.location.place?.address ?? "" - ) - .onAppear { - if index == trackList.count - 1 - && trackUseCase.feedListHasNext { - fetchNextPage() - } - } - } - } - } - + FeedList( + isNonePlaylistToastPresented: $isNonePlaylistToastPresented, + isLoading: $isLoading + ) + if musicControlUseCase.state.isStreaming { MiniMusicPlayer( isPaused: $musicControlUseCase.state.isPaused, @@ -110,29 +38,87 @@ struct TrackFeedView: View { currentDuration: musicControlUseCase.state.currentDuration, totalDuration: musicControlUseCase.state.currentTrack?.music.duration ?? 0 ) - .onTapGesture { - if let selectedTrackId = musicControlUseCase.state.currentTrack?.id { - miniMusicPlayerTapped(with: Int(selectedTrackId)) - } - } + .onTapGesture(perform: miniMusicPlayerTapped) } } .background(.platBackground) - VStack { - Spacer() + ToastMessage( + message: "트랙을 추가할 플레이리스트가 없어요.", + isToastPresented: $isNonePlaylistToastPresented + ) + } + .overlay(PlatProgressView(isLoading: isLoading)) + .onDisappear(perform: trackUseCase.resetFeed) + } + + /// MiniMusicPlayer를 탭합니다. + private func miniMusicPlayerTapped() { + if let selectedTrackId = musicControlUseCase.state.currentTrack?.id { + Task { + try await fetchSelectedTrack(with: Int(selectedTrackId)) + } + } + } + + /// 선택한 Track 정보를 Fetch합니다. + private func fetchSelectedTrack(with trackId: Int) async throws { + let updateCurrentTrackResult = await trackUseCase.fetchCurrentTrack(from: trackId) + switch updateCurrentTrackResult { + case .success(let fetchTrack): + let musicResult = await musicControlUseCase.fetchMusic(from: fetchTrack) + switch musicResult { + case .success(let music): + trackUseCase.updateCurrentTrackMusicInfo(from: music) + let currentTrack = trackUseCase.currentTrack + musicControlUseCase.updateCurrentTrack(to: currentTrack) + pathModel.presentFullScreenCover(.trackDetail) - ToastMessage( - message: "트랙을 추가할 플레이리스트가 없어요.", - isToastPresented: $isNonePlaylistToastPresented - ) - .padding(.bottom, 30) + case .failure(let error): throw error + } + case .failure(let error): throw error + } + } +} + +// MARK: - FeedList + +private struct FeedList: View { + + @Environment(TrackUseCase.self) private var trackUseCase + @Environment(MusicControlUseCase.self) private var musicControlUseCase + + @Binding private(set) var isNonePlaylistToastPresented: Bool + @Binding private(set) var isLoading: Bool + + /// 트랙 리스트를 반환합니다. + private var trackList: [Track] { + trackUseCase.feedTrackList.filter { + let reportedTrackIdList = UserDefaults.standard.reportedTrackIdList + return !reportedTrackIdList.contains($0.id) + } + } + + var body: some View { + @Bindable var musicControlUseCase = musicControlUseCase + ScrollView { + LazyVStack { + ForEach(Array(trackList.enumerated()), id: \.offset) { index, track in + FeedRowView( + currentTrack: $musicControlUseCase.state.currentTrack, + isLoading: $isLoading, + isNonePlaylistToastPresented: $isNonePlaylistToastPresented, + track: track, + address: track.location.place?.address ?? "" + ) + .onAppear { + if index == trackList.count - 1 && trackUseCase.feedListHasNext { + fetchNextPage() + } + } + } } } - .overlay( - PlatProgressView() - .opacity(isLoading ? 1 : 0) - ) .onAppear { Task { let trackList = await trackUseCase.fetchFeedTrackList() @@ -146,8 +132,26 @@ struct TrackFeedView: View { try await updateFeed(from: trackList) } } - .onDisappear { - trackUseCase.resetFeed() + } + + /// Feed를 업데이트합니다. + private func updateFeed(from trackList: [Track]) async throws { + let fetchMusicListResult = await musicControlUseCase.fetchMusicList(from: trackList) + + switch fetchMusicListResult { + case .success(let musicList): + trackUseCase.updateFeedTrackListMusicInfo(from: musicList) + + case .failure(let error): + throw error + } + } + + /// 다음 페이지를 Fetch합니다. + private func fetchNextPage() { + Task { + let trackList = await trackUseCase.paginationFeedTrackList() + try await updateFeed(from: trackList) } } } @@ -169,7 +173,6 @@ private struct FeedRowView: View { @Binding private(set) var isNonePlaylistToastPresented: Bool let track: Track - let playlistId: String let address: String? var body: some View { @@ -247,16 +250,12 @@ private struct MenuButton: View { var body: some View { Menu { if authUseCase.checkMyTrack(currentTrack: track) { - Button(role: .destructive) { + Button("삭제하기", role: .destructive) { isDeleteAlertPresented.toggle() - } label: { - Text("삭제하기") } } else { - Button(role: .destructive) { + Button("신고하기", role: .destructive) { pathModel.push(.report(trackId: track.id)) - } label: { - Text("신고하기") } } } label: { @@ -290,6 +289,8 @@ private struct MenuButton: View { private struct FeedProfileImage: View { + private let size: CGFloat = 40 + let track: Track private var profileImageUrl: URL? { @@ -300,12 +301,12 @@ private struct FeedProfileImage: View { KFImage(profileImageUrl) .placeholder { Circle() - .frame(width: 40, height: 40) + .frame(width: size, height: size) .foregroundStyle(.gray9) } .resizable() .scaledToFill() - .frame(width: 40, height: 40) + .frame(width: size, height: size) .clipShape(Circle()) } } @@ -328,7 +329,6 @@ private struct FeedHeaderView: View { Text(track.createdDate.monthDayYearFormat) .font(.Body.body5) .foregroundStyle(.white) - } } } @@ -481,7 +481,7 @@ private struct FeedContentImage: View { .overlay { KFImage(URL(string: imageUrl)) .placeholder { - PlatProgressView() + PlatProgressView(isLoading: true) } .cancelOnDisappear(true) .resizable()