From 4d61911919b32827633d1a894c84644a13956a58 Mon Sep 17 00:00:00 2001 From: lina Date: Fri, 4 Oct 2024 17:44:56 +0900 Subject: [PATCH 1/8] =?UTF-8?q?fix:=20=EB=A6=AC=EC=A0=9D=20=EB=8C=80?= =?UTF-8?q?=EC=9D=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Endpoint/MemeEndpoint.swift | 2 +- .../MemeDetail/Sources/MemeDetailView.swift | 63 +++++++++++---- .../Sources/MemeDetailViewModel.swift | 80 ++++++++----------- .../Sources/Presentation/RecommendView.swift | 7 +- .../Presentation/RecommendViewModel.swift | 2 +- 5 files changed, 86 insertions(+), 68 deletions(-) diff --git a/Projects/Core/PPACData/Sources/Endpoint/MemeEndpoint.swift b/Projects/Core/PPACData/Sources/Endpoint/MemeEndpoint.swift index e41731e..6c01d39 100644 --- a/Projects/Core/PPACData/Sources/Endpoint/MemeEndpoint.swift +++ b/Projects/Core/PPACData/Sources/Endpoint/MemeEndpoint.swift @@ -54,7 +54,7 @@ public enum MemeEndpoint: Requestable { return "/meme/recommend-memes" case .getSearchKeywordMemeList(_,_,let keyword): return "/meme/search/\(keyword)" - case .getSearchByTextMemeList(_,_,let text): + case .getSearchByTextMemeList(_,_,_): return "/meme/search" case .meme(let memeId): return "/meme/\(memeId)" diff --git a/Projects/Features/MemeDetail/Sources/MemeDetailView.swift b/Projects/Features/MemeDetail/Sources/MemeDetailView.swift index 1f19ba0..2e1d9a6 100644 --- a/Projects/Features/MemeDetail/Sources/MemeDetailView.swift +++ b/Projects/Features/MemeDetail/Sources/MemeDetailView.swift @@ -27,7 +27,10 @@ public struct MemeDetailView: View { @State private var totalHeight: CGFloat = 0 @State private var memeCardHeight: CGFloat = 0 @State private var tabBarHeight: CGFloat = 0 - + @State private var isSheetPresented: Bool = false + @State private var isWebViewPresented: Bool = false + @State private var showContactUsAlert: Bool = false + private var isShortCard: Bool { memeCardHeight + tabBarHeight > totalHeight - 30 } @@ -43,8 +46,14 @@ public struct MemeDetailView: View { public var body: some View { ZStack { memeDetailCardView - if viewModel.state.isSheetPresented { + .sheet(isPresented: $isSheetPresented) { + bottomSheetView + .presentationDetents([.height(66+40)]) + } + + if isSheetPresented { Color.black.opacity(0.4) + .ignoresSafeArea([.container]) } } .onAppear { @@ -52,10 +61,27 @@ public struct MemeDetailView: View { } .plainNavigationBar( backHandler: { viewModel.dispatch(type: .naviBackButtonTapped) }, - rightActionHandler: { viewModel.dispatch(type: .naviMoreButtonTapped) }, + rightActionHandler: { isSheetPresented = true }, hasConfigureButton: true, title: viewModel.state.meme.title ) + .sheet(isPresented: $isWebViewPresented, onDismiss: { isWebViewPresented = false }) { + WebView(url: viewModel.state.reportProblemUrl) + .presentationDetents([.large]) + } + .basicModal( + isPresented: $showContactUsAlert, + opacity: 0.5, + content: { + FarmemeAlertView( + title: "문의하기", + description: "jhr110326@gmail.com", + dismiss: { + showContactUsAlert = false + } + ) + } + ) .popup( isActive: $viewModel.state.isCopied, image: ResourceKitAsset.Icon.copyFilled.swiftUIImage, @@ -66,16 +92,6 @@ public struct MemeDetailView: View { image: viewModel.state.meme.isFarmemed ? ResourceKitAsset.Icon.copyFilled.swiftUIImage : nil, text: viewModel.state.meme.isFarmemed ? "파밈 완료!" : "파밈을 취소했어요" ) - .sheet(isPresented: $viewModel.state.isSheetPresented) { - ZStack(alignment: .bottom) { - bottomSheetView - .presentationDetents([.height(66)]) - } - } - .sheet(isPresented: $viewModel.state.isWebViewPresented) { - WebView(url: viewModel.state.reportProblemUrl) - .presentationDetents([.large]) - } } private var memeDetailCardView: some View { @@ -153,11 +169,18 @@ public struct MemeDetailView: View { .frame(height: 16) .foregroundStyle(Color.Background.white) reportProblembutton + .onTapGesture { + isSheetPresented = false + isWebViewPresented = true + } + contactUsButton + .onTapGesture { + isSheetPresented = false + isWebViewPresented = false // 신고하기 후에 누르면, 신고하기가 떠서 강제로 막음 + showContactUsAlert = true + } } .padding(.bottom, 10) - .onTapGesture { - viewModel.dispatch(type: .reportProblemButtonTapped) - } } private var reportProblembutton: some View { @@ -167,6 +190,13 @@ public struct MemeDetailView: View { .padding(.vertical, 16) } + private var contactUsButton: some View { + Text("문의하기") + .font(Font.Body.Xlarge.medium) + .foregroundStyle(Color.Text.primary) + .padding(.vertical, 16) + } + @MainActor private func tabBarTap(_ type: MemeDetailTab) { switch type { @@ -178,7 +208,6 @@ public struct MemeDetailView: View { viewModel.dispatch(type: .shreButtonTapped) } } - } #Preview { diff --git a/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift b/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift index 619e58e..d4c6954 100644 --- a/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift +++ b/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift @@ -29,17 +29,12 @@ public final class MemeDetailViewModel: ViewModelType, ObservableObject { case shreButtonTapped case farmemeButtonTapped case naviBackButtonTapped - case naviMoreButtonTapped - case reportProblemButtonTapped } public struct State { var meme: MemeDetail var isCopied: Bool = false var isFarmemeChanged: Bool = false - var isSheetPresented: Bool = false - var isWebViewPresented: Bool = false - let reportProblemUrl: URL? = URL(string: "https://forms.gle/a5QkMnLD8AANtYCo7") } @@ -57,8 +52,6 @@ public final class MemeDetailViewModel: ViewModelType, ObservableObject { private var reactionTask: Task? private let trotller = Throttler(seconds: 3) - - // MARK: - Initializers @@ -70,7 +63,7 @@ public final class MemeDetailViewModel: ViewModelType, ObservableObject { watchMemeUseCase: WatchMemeUseCase, reactToMemeUseCase: ReactToMemeUseCase ) { - print("memeviewmodel init") + debugPrint("memeviewmodel init") self.router = router self.state = State(meme: meme) self.bookmarkMemeUseCase = bookmarkMemeUseCase @@ -80,18 +73,18 @@ public final class MemeDetailViewModel: ViewModelType, ObservableObject { } deinit { - print("memeviewmodel deinit") - reactionTask?.cancel() + debugPrint("memeviewmodel deinit") + reactionTask?.cancel() } // MARK: - Methods public func dispatch(type: Action) { Task { @MainActor in - print("type: \(type)") + debugPrint("type: \(type)") switch type { case .likeButtonTapped: - await postReaction() + postReaction() case .copyButtonTapped: await copyImage() case .shreButtonTapped: @@ -104,12 +97,6 @@ public final class MemeDetailViewModel: ViewModelType, ObservableObject { } case .naviBackButtonTapped: router?.popView() - case .naviMoreButtonTapped: - state.isSheetPresented = true - case .reportProblemButtonTapped: - state.isSheetPresented = false - state.isWebViewPresented = true - print("reportProblemButtonTapped") } } } @@ -130,37 +117,36 @@ public final class MemeDetailViewModel: ViewModelType, ObservableObject { } private extension MemeDetailViewModel { - + @MainActor func postReaction() { - reactionCount += 1 - self.state.meme.reaction += 1 - self.state.meme.isReaction = true - self.logMemeDetail(event: .reaction) + reactionCount += 1 + self.state.meme.reaction += 1 + self.state.meme.isReaction = true + self.logMemeDetail(event: .reaction) - trotller.throttle { - await self.sendReactions() - } + trotller.throttle { + await self.sendReactions() + } } - - + @MainActor func sendReactions() async { - let count = reactionCount - guard count > 0 else { - // 전송할 리액션이 없음 - return - } - reactionCount = 0 - do { - let count = try await reactToMemeUseCase.execute(memeId: state.meme.id, count: count) - print("currentMeme count: \(self.state.meme.reaction)") - print("new count: \(count)") - self.state.meme.reaction = count - print("Reactions sent successfully with count: \(count)") - } catch { - print("Failed to send reactions: \(error)") - } + let count = reactionCount + guard count > 0 else { + // 전송할 리액션이 없음 + return + } + reactionCount = 0 + do { + let count = try await reactToMemeUseCase.execute(memeId: state.meme.id, count: count) + debugPrint("currentMeme count: \(self.state.meme.reaction)") + debugPrint("new count: \(count)") + self.state.meme.reaction = count + debugPrint("Reactions sent successfully with count: \(count)") + } catch { + debugPrint("Failed to send reactions: \(error)") + } } @MainActor @@ -177,7 +163,7 @@ private extension MemeDetailViewModel { state.isCopied = true self.logMemeDetail(event: .copy) } catch { - print("Failed to load image data: \(error)") + debugPrint("Failed to load image data: \(error)") } } @@ -192,7 +178,7 @@ private extension MemeDetailViewModel { self.logMemeDetail(event: .save) } catch { // TODO: - 에러처리 - print(error) + debugPrint(error) } } @@ -207,7 +193,7 @@ private extension MemeDetailViewModel { self.logMemeDetail(event: .saveCancel) } catch { // TODO: - 에러처리 - print(error) + debugPrint(error) } } @@ -220,7 +206,7 @@ private extension MemeDetailViewModel { self.logMemeDetail(event: .share) } catch { // TODO: - 에러처리 - print(error) + debugPrint(error) } } } diff --git a/Projects/Features/Recommend/Sources/Presentation/RecommendView.swift b/Projects/Features/Recommend/Sources/Presentation/RecommendView.swift index d4d67e4..3190545 100644 --- a/Projects/Features/Recommend/Sources/Presentation/RecommendView.swift +++ b/Projects/Features/Recommend/Sources/Presentation/RecommendView.swift @@ -18,8 +18,6 @@ import PPACNetwork import DesignSystem - - public struct RecommendView: View { @ObservedObject private var viewModel: RecommendViewModel @@ -71,6 +69,11 @@ public struct RecommendView: View { .onReadSize { size in memeImageHeight = size.height } + .onTapGesture { + if let currentMeme { + viewModel.router?.showMemeDetailView(meme: currentMeme) + } + } Spacer() } diff --git a/Projects/Features/Recommend/Sources/Presentation/RecommendViewModel.swift b/Projects/Features/Recommend/Sources/Presentation/RecommendViewModel.swift index d6d613b..59b0bed 100644 --- a/Projects/Features/Recommend/Sources/Presentation/RecommendViewModel.swift +++ b/Projects/Features/Recommend/Sources/Presentation/RecommendViewModel.swift @@ -143,7 +143,7 @@ private extension RecommendViewModel { @MainActor func getRecommendAndUser() async { do { - let recommendMemeSize = 5 + let recommendMemeSize = 20 let recommendMemes = try await getRecommendMemesUseCase.execute(size: recommendMemeSize) let user = try await getUserInfoUseCase.execute() print("👍memeids: \(recommendMemes.map { $0.id })") From fc1c9a48e3277a9ae320dc0a05d77af5f4475cb5 Mon Sep 17 00:00:00 2001 From: lina Date: Fri, 4 Oct 2024 18:05:16 +0900 Subject: [PATCH 2/8] =?UTF-8?q?fix:=20=EA=B2=80=EC=83=89=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EB=A6=AC=ED=94=84=EB=A0=88=EC=8B=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Search/Sources/View/Result/SearchResultView.swift | 3 +++ .../Sources/View/Result/SearchResultViewModel.swift | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/Projects/Features/Search/Sources/View/Result/SearchResultView.swift b/Projects/Features/Search/Sources/View/Result/SearchResultView.swift index 4202306..43e4ba1 100644 --- a/Projects/Features/Search/Sources/View/Result/SearchResultView.swift +++ b/Projects/Features/Search/Sources/View/Result/SearchResultView.swift @@ -53,6 +53,9 @@ public struct SearchResultView: View { } } } + .refreshable { + viewModel.dispatch(type: .refresh) + } } .onAppear { viewModel.dispatch(type: .viewWillAppear) diff --git a/Projects/Features/Search/Sources/View/Result/SearchResultViewModel.swift b/Projects/Features/Search/Sources/View/Result/SearchResultViewModel.swift index 8c098e5..85c03e4 100644 --- a/Projects/Features/Search/Sources/View/Result/SearchResultViewModel.swift +++ b/Projects/Features/Search/Sources/View/Result/SearchResultViewModel.swift @@ -27,6 +27,7 @@ public final class SearchResultViewModel: ViewModelType, ObservableObject { public enum Action { case viewWillAppear + case refresh case search(text: String) case memeDetailTapped(meme: MemeDetail) case memeCopyTapped(meme: MemeDetail) @@ -85,6 +86,13 @@ public final class SearchResultViewModel: ViewModelType, ObservableObject { switch type { case .viewWillAppear: await fetchData() + case .refresh: + if state.text.isEmpty == false { + await fetchData(with: state.text) + } else if state.keyword.isEmpty == false { + await fetchData(with: state.keyword) + } + case .search(text: let text): await fetchData(with: text) case .memeDetailTapped(let meme): From 1b64d8ee59cb13744649c6a958d1a6389843c58b Mon Sep 17 00:00:00 2001 From: lina Date: Fri, 4 Oct 2024 18:14:24 +0900 Subject: [PATCH 3/8] =?UTF-8?q?fix:=20=EB=B0=88=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=8B=AB=EC=9D=84=EB=95=8C=20reaction=20s?= =?UTF-8?q?end=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift b/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift index d4c6954..a3572e5 100644 --- a/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift +++ b/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift @@ -96,6 +96,7 @@ public final class MemeDetailViewModel: ViewModelType, ObservableObject { await postSavedFarmeme() } case .naviBackButtonTapped: + await sendReactions() router?.popView() } } From bea74ba5526ffd148d2d667611b6abe21cbf3ebf Mon Sep 17 00:00:00 2001 From: lina Date: Fri, 4 Oct 2024 18:14:50 +0900 Subject: [PATCH 4/8] =?UTF-8?q?fix:=20meme=20category=20view=20>=20alignme?= =?UTF-8?q?nt=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DesignSystem/Sources/View/Keyword/MemeCategoryView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects/Core/DesignSystem/Sources/View/Keyword/MemeCategoryView.swift b/Projects/Core/DesignSystem/Sources/View/Keyword/MemeCategoryView.swift index a96cf96..1e7f468 100644 --- a/Projects/Core/DesignSystem/Sources/View/Keyword/MemeCategoryView.swift +++ b/Projects/Core/DesignSystem/Sources/View/Keyword/MemeCategoryView.swift @@ -24,7 +24,7 @@ public struct MemeCategoryView: View { } public var body: some View { - VStack(spacing: 0) { + VStack(alignment: .leading, spacing: 0) { HStack { Text(category) .font(Font.Body.Small.semiBold) From aa178543cd38bfc3b25def07576e4f1b63779c8c Mon Sep 17 00:00:00 2001 From: lina Date: Fri, 4 Oct 2024 19:28:57 +0900 Subject: [PATCH 5/8] =?UTF-8?q?fix:=20=EB=AC=B8=EC=9D=98=ED=95=98=EA=B8=B0?= =?UTF-8?q?=20=EB=A9=94=EC=9D=BC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/Features/MemeDetail/Sources/MemeDetailView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects/Features/MemeDetail/Sources/MemeDetailView.swift b/Projects/Features/MemeDetail/Sources/MemeDetailView.swift index 2e1d9a6..899f05f 100644 --- a/Projects/Features/MemeDetail/Sources/MemeDetailView.swift +++ b/Projects/Features/MemeDetail/Sources/MemeDetailView.swift @@ -75,7 +75,7 @@ public struct MemeDetailView: View { content: { FarmemeAlertView( title: "문의하기", - description: "jhr110326@gmail.com", + description: "farmemebusiness@gmail.com", dismiss: { showContactUsAlert = false } From 1cdd6a30a16c1f0e59e765c308c444d0dfe94ba9 Mon Sep 17 00:00:00 2001 From: lina Date: Fri, 4 Oct 2024 19:29:27 +0900 Subject: [PATCH 6/8] =?UTF-8?q?fix:=20endTextEditing=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/Features/MemeEditor/Sources/MemeEditorView.swift | 1 + Projects/Features/Search/Sources/View/SearchView.swift | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Projects/Features/MemeEditor/Sources/MemeEditorView.swift b/Projects/Features/MemeEditor/Sources/MemeEditorView.swift index 2f5f01f..02c292a 100644 --- a/Projects/Features/MemeEditor/Sources/MemeEditorView.swift +++ b/Projects/Features/MemeEditor/Sources/MemeEditorView.swift @@ -144,6 +144,7 @@ struct MemeEditorView: View { keywordTags: keywordTags ) { keyword in viewModel.dispatch(type: .memeKeywordTapped(keyword: keyword)) + endTextEditing() } } .id(viewModel.state.memeCategories.count) diff --git a/Projects/Features/Search/Sources/View/SearchView.swift b/Projects/Features/Search/Sources/View/SearchView.swift index d691f4f..117f183 100644 --- a/Projects/Features/Search/Sources/View/SearchView.swift +++ b/Projects/Features/Search/Sources/View/SearchView.swift @@ -51,6 +51,9 @@ public struct SearchView: View { .frame(height: 64 + 50) } .scrollIndicators(.hidden) + .onTapGesture { + endTextEditing() + } } .onAppear { viewModel.dispatch(type: .viewWillAppear) From 2229ba9cf0c704e812090bd8bf7766eaa19c53e1 Mon Sep 17 00:00:00 2001 From: lina Date: Fri, 4 Oct 2024 19:47:43 +0900 Subject: [PATCH 7/8] =?UTF-8?q?fix:=20=EC=B6=94=EC=B2=9C=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EB=A7=A4=EB=B2=88=20=EB=A6=AC=ED=94=84=EB=A0=88?= =?UTF-8?q?=EC=8B=9C=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Recommend/Sources/Presentation/RecommendView.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Projects/Features/Recommend/Sources/Presentation/RecommendView.swift b/Projects/Features/Recommend/Sources/Presentation/RecommendView.swift index 3190545..eff5181 100644 --- a/Projects/Features/Recommend/Sources/Presentation/RecommendView.swift +++ b/Projects/Features/Recommend/Sources/Presentation/RecommendView.swift @@ -129,6 +129,9 @@ public struct RecommendView: View { ) ) .edgesIgnoringSafeArea(.bottom) + .onAppear { + viewModel.dispatch(type: .viewInitialized) + } .onChange(of: viewModel.state.isSuccessFetch) { withAnimation(.spring()) { currentOffsetY = viewModel.state.isSuccessFetch ? .zero : 20 From 5edee4e4481311a94b6dcb79626b61b6403f3367 Mon Sep 17 00:00:00 2001 From: lina Date: Fri, 4 Oct 2024 20:15:44 +0900 Subject: [PATCH 8/8] =?UTF-8?q?feat:=20=EA=B2=80=EC=83=89=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20>=20=EB=B0=88=20=EC=83=81=EC=84=B8=20=EA=B0=94?= =?UTF-8?q?=EB=8B=A4=EC=98=A8=20=ED=9B=84=20=ED=95=B4=EB=8B=B9=20=EB=B0=88?= =?UTF-8?q?=EB=A7=8C=20=EB=A6=AC=ED=94=84=EB=A0=88=EC=8B=9C=20=EB=90=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/Result/SearchResultRouter.swift | 3 ++- .../View/Result/SearchResultViewModel.swift | 23 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Projects/Features/Search/Sources/View/Result/SearchResultRouter.swift b/Projects/Features/Search/Sources/View/Result/SearchResultRouter.swift index 17b10c5..e2fe137 100644 --- a/Projects/Features/Search/Sources/View/Result/SearchResultRouter.swift +++ b/Projects/Features/Search/Sources/View/Result/SearchResultRouter.swift @@ -46,7 +46,8 @@ public final class SearchResultRouter: Router, SearchResultRouting { text: text, router: self, searchKeywordUseCase: SearchKeywordUseCaseImpl(repository: repository), - searchByTextUseCase: SearchByTextUseCaseImpl(repository: repository), + searchByTextUseCase: SearchByTextUseCaseImpl(repository: repository), + getMemeDetailUseCase: GetMemeDetailUseCaseImpl(repository: repository), copyImageUseCase: CopyImageUseCaseImpl(), watchMemeUseCase: WatchMemeUseCaseImpl(repository: repository) )) diff --git a/Projects/Features/Search/Sources/View/Result/SearchResultViewModel.swift b/Projects/Features/Search/Sources/View/Result/SearchResultViewModel.swift index 85c03e4..b70af83 100644 --- a/Projects/Features/Search/Sources/View/Result/SearchResultViewModel.swift +++ b/Projects/Features/Search/Sources/View/Result/SearchResultViewModel.swift @@ -40,6 +40,7 @@ public final class SearchResultViewModel: ViewModelType, ObservableObject { var text: String var memeList: [MemeDetail] var memePagination: MemeListWithPagination.Pagination + var currentMeme: MemeDetail? var isActiveCopyPopup: Bool = false var isLoading: Bool = true } @@ -51,6 +52,7 @@ public final class SearchResultViewModel: ViewModelType, ObservableObject { private let searchKeywordUseCase: SearchKeywordUseCase private let searchByTextUseCase: SearchByTextUseCase + private let getMemeDetailUseCase: GetMemeDetailUseCase private let copyImageUseCase: CopyImageUseCase private let watchMemeUseCase: WatchMemeUseCase @@ -62,6 +64,7 @@ public final class SearchResultViewModel: ViewModelType, ObservableObject { router: SearchResultRouting?, searchKeywordUseCase: SearchKeywordUseCase, searchByTextUseCase: SearchByTextUseCase, + getMemeDetailUseCase: GetMemeDetailUseCase, copyImageUseCase: CopyImageUseCase, watchMemeUseCase: WatchMemeUseCase ) { @@ -74,6 +77,7 @@ public final class SearchResultViewModel: ViewModelType, ObservableObject { ) self.searchKeywordUseCase = searchKeywordUseCase self.searchByTextUseCase = searchByTextUseCase + self.getMemeDetailUseCase = getMemeDetailUseCase self.copyImageUseCase = copyImageUseCase self.watchMemeUseCase = watchMemeUseCase } @@ -86,19 +90,20 @@ public final class SearchResultViewModel: ViewModelType, ObservableObject { switch type { case .viewWillAppear: await fetchData() + await refreshCurrentMeme() case .refresh: if state.text.isEmpty == false { await fetchData(with: state.text) } else if state.keyword.isEmpty == false { await fetchData(with: state.keyword) } - case .search(text: let text): await fetchData(with: text) case .memeDetailTapped(let meme): router?.showMemeDetail(memeDetail: meme) logSearch(event: .meme, keyword: state.keyword) await postShownMeme(memeId: meme.id) + state.currentMeme = meme case .memeCopyTapped(let meme): await copyImage(meme: meme) break @@ -162,6 +167,22 @@ public final class SearchResultViewModel: ViewModelType, ObservableObject { } } + @MainActor + private func refreshCurrentMeme() async { + guard let currentMeme = state.currentMeme else { return } + + do { + let meme = try await getMemeDetailUseCase.execute(memeId: currentMeme.id) + if let index = state.memeList.firstIndex(where: { $0.id == meme.id }) { + state.memeList[index] = meme + } + } catch(let error) { + debugPrint("error = \(error)") + } + + state.currentMeme = nil + } + @MainActor private func copyImage(meme: MemeDetail) async { do {