From b0a707aacce6f8240606f695def2886efe6bb0df Mon Sep 17 00:00:00 2001 From: chansooo Date: Tue, 1 Oct 2024 23:34:56 +0900 Subject: [PATCH 1/7] =?UTF-8?q?fix:=20watch=20=ED=95=84=EB=93=9C=20optiona?= =?UTF-8?q?l=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/Core/PPACData/Sources/DTO/MemeResponseDTO.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects/Core/PPACData/Sources/DTO/MemeResponseDTO.swift b/Projects/Core/PPACData/Sources/DTO/MemeResponseDTO.swift index dc3cdb3..191f86d 100644 --- a/Projects/Core/PPACData/Sources/DTO/MemeResponseDTO.swift +++ b/Projects/Core/PPACData/Sources/DTO/MemeResponseDTO.swift @@ -55,7 +55,7 @@ struct MemeResponseDTO: Decodable { let updatedAt: String let isSaved: Bool let isReaction: Bool - let watch: Int + let watch: Int? public init( _id: String, From a932693e018d0d7fc732f8dd69af220703f251a1 Mon Sep 17 00:00:00 2001 From: chansooo Date: Wed, 2 Oct 2024 00:26:37 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20MemeReactionRequestDTO=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/DTO/MemeReactionRequestDTO.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Projects/Core/PPACData/Sources/DTO/MemeReactionRequestDTO.swift diff --git a/Projects/Core/PPACData/Sources/DTO/MemeReactionRequestDTO.swift b/Projects/Core/PPACData/Sources/DTO/MemeReactionRequestDTO.swift new file mode 100644 index 0000000..8e2f0e5 --- /dev/null +++ b/Projects/Core/PPACData/Sources/DTO/MemeReactionRequestDTO.swift @@ -0,0 +1,16 @@ +// +// MemeReactionRequestDTO.swift +// PPACData +// +// Created by kimchansoo on 10/1/24. +// + +import Foundation + +public struct MemeReactionRequestDTO: Codable { + public let count: Int + + public init(count: Int) { + self.count = count + } +} From fea0d386df06dedf3db17f46896f0dd36758e78f Mon Sep 17 00:00:00 2001 From: chansooo Date: Wed, 2 Oct 2024 00:27:15 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20reaction=20count=EB=A7=8C=ED=81=BC?= =?UTF-8?q?=20=EC=98=AC=EB=A6=AC=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/PPACData/Sources/Endpoint/MemeEndpoint.swift | 10 +++++----- .../Sources/Repository/MemeRepositoryImpl.swift | 4 ++-- .../PPACDomain/Sources/Repository/MemeRepository.swift | 2 +- .../Sources/UseCase/Meme/ReactToMemeUseCase.swift | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Projects/Core/PPACData/Sources/Endpoint/MemeEndpoint.swift b/Projects/Core/PPACData/Sources/Endpoint/MemeEndpoint.swift index a845369..a39dfe5 100644 --- a/Projects/Core/PPACData/Sources/Endpoint/MemeEndpoint.swift +++ b/Projects/Core/PPACData/Sources/Endpoint/MemeEndpoint.swift @@ -18,7 +18,7 @@ public enum MemeEndpoint: Requestable { case deleteBookmark(memeId: String) case share(memeId: String) case watch(memeId: String, type: String) - case reaction(memeId: String) + case reaction(memeId: String, count: Int) public var httpMethod: PPACNetwork.HTTPMethod { switch self { @@ -61,8 +61,8 @@ public enum MemeEndpoint: Requestable { return "/meme/\(memeId)/share" case .watch(let memeId, let type): return "/meme/\(memeId)/watch/\(type)" - case .reaction(let memeId): - return "/meme/\(memeId)/reaction" + case .reaction(let memeId, _): + return "meme/\(memeId)/reaction" } } @@ -85,8 +85,8 @@ public enum MemeEndpoint: Requestable { return nil case .watch: return nil - case .reaction: - return nil + case let .reaction(memeId, count): + return .body(MemeReactionRequestDTO(count: count)) case .meme(memeId: _): return nil } diff --git a/Projects/Core/PPACData/Sources/Repository/MemeRepositoryImpl.swift b/Projects/Core/PPACData/Sources/Repository/MemeRepositoryImpl.swift index c55da72..41079c1 100644 --- a/Projects/Core/PPACData/Sources/Repository/MemeRepositoryImpl.swift +++ b/Projects/Core/PPACData/Sources/Repository/MemeRepositoryImpl.swift @@ -114,8 +114,8 @@ public class MemeRepositoryImpl: MemeRepository { } } - public func reactToMeme(memeId: String) async throws { - let endpoint = MemeEndpoint.reaction(memeId: memeId) + public func reactToMeme(memeId: String, count: Int) async throws { + let endpoint = MemeEndpoint.reaction(memeId: memeId, count: count) let result = await networkservice.request(endpoint, dataType: BaseDTO.self) switch result { case .success: diff --git a/Projects/Core/PPACDomain/Sources/Repository/MemeRepository.swift b/Projects/Core/PPACDomain/Sources/Repository/MemeRepository.swift index a3a7eef..8d880c1 100644 --- a/Projects/Core/PPACDomain/Sources/Repository/MemeRepository.swift +++ b/Projects/Core/PPACDomain/Sources/Repository/MemeRepository.swift @@ -19,7 +19,7 @@ public protocol MemeRepository { func deleteBookmarkMeme(memeId: String) async throws func shareMeme(memeId: String) async throws func watchMeme(memeId: String, type: String) async throws - func reactToMeme(memeId: String) async throws + func reactToMeme(memeId: String, count: Int) async throws func registerMeme(formData: FormData, title: String, source: String, keywordIds: [String]) async throws } diff --git a/Projects/Core/PPACDomain/Sources/UseCase/Meme/ReactToMemeUseCase.swift b/Projects/Core/PPACDomain/Sources/UseCase/Meme/ReactToMemeUseCase.swift index 79858bd..26987bf 100644 --- a/Projects/Core/PPACDomain/Sources/UseCase/Meme/ReactToMemeUseCase.swift +++ b/Projects/Core/PPACDomain/Sources/UseCase/Meme/ReactToMemeUseCase.swift @@ -10,7 +10,7 @@ import Foundation import PPACModels public protocol ReactToMemeUseCase { - func execute(memeId: String) async throws + func execute(memeId: String, count: Int) async throws } public class ReactToMemeUseCaseImpl: ReactToMemeUseCase { @@ -20,7 +20,7 @@ public class ReactToMemeUseCaseImpl: ReactToMemeUseCase { self.repository = repository } - public func execute(memeId: String) async throws { - try await repository.reactToMeme(memeId: memeId) + public func execute(memeId: String, count: Int) async throws { + try await repository.reactToMeme(memeId: memeId, count: count) } } From 361747841df61865aeab54f4b4263e56ef6162b7 Mon Sep 17 00:00:00 2001 From: chansooo Date: Wed, 2 Oct 2024 00:27:49 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=203=EC=B4=88=20throttle=EB=8F=99?= =?UTF-8?q?=EC=95=88=20=EB=93=A4=EC=96=B4=EC=98=A4=EB=8A=94=20count=20?= =?UTF-8?q?=ED=95=9C=20=EB=B2=88=EC=97=90=20=EB=B3=B4=EB=82=B4=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/MemeDetailViewModel.swift | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift b/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift index 6248497..dc7342a 100644 --- a/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift +++ b/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift @@ -47,6 +47,9 @@ public final class MemeDetailViewModel: ViewModelType, ObservableObject { private let watchMemeUseCase: WatchMemeUseCase private let reactToMemeUseCase: ReactToMemeUseCase + private var reactionCount = 0 + private var reactionTask: Task? + // MARK: - Initializers public init( @@ -67,7 +70,8 @@ public final class MemeDetailViewModel: ViewModelType, ObservableObject { } deinit { - print("memeviewmodel deinit") + print("memeviewmodel deinit") + reactionTask?.cancel() } // MARK: - Methods @@ -110,19 +114,47 @@ public final class MemeDetailViewModel: ViewModelType, ObservableObject { } private extension MemeDetailViewModel { - + @MainActor - func postReaction() async { - do { - try await reactToMemeUseCase.execute(memeId: state.meme.id) + func postReaction() { + reactionCount += 1 self.state.meme.reaction += 1 self.state.meme.isReaction = true self.logMemeDetail(event: .reaction) - print("reaction success") - } catch { - // TODO: - 에러처리 - print("Failed to post reaction: \(error)") - } + + reactionTask?.cancel() + + reactionTask = Task { [weak self] in + guard let self = self else { return } + do { + try await Task.sleep(nanoseconds: 3 * 1_000_000_000) + await self.sendReactions() + } catch { + if Task.isCancelled { + // 태스크가 취소되었으므로 아무 작업도 하지 않음 + return + } else { + print("Task error: \(error)") + } + } + } + } + + + @MainActor + func sendReactions() async { + let count = reactionCount + guard count > 0 else { + // 전송할 리액션이 없음 + return + } + reactionCount = 0 + do { + try await reactToMemeUseCase.execute(memeId: state.meme.id, count: count) + print("Reactions sent successfully with count: \(count)") + } catch { + print("Failed to send reactions: \(error)") + } } @MainActor From ccbe62f998e703838179c0a405476dae6394bc3e Mon Sep 17 00:00:00 2001 From: chansooo Date: Wed, 2 Oct 2024 00:33:08 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20MemeReactionResponseDTO=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PPACData/Sources/DTO/MemeReactionRequestDTO.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Projects/Core/PPACData/Sources/DTO/MemeReactionRequestDTO.swift b/Projects/Core/PPACData/Sources/DTO/MemeReactionRequestDTO.swift index 8e2f0e5..28ceaef 100644 --- a/Projects/Core/PPACData/Sources/DTO/MemeReactionRequestDTO.swift +++ b/Projects/Core/PPACData/Sources/DTO/MemeReactionRequestDTO.swift @@ -14,3 +14,11 @@ public struct MemeReactionRequestDTO: Codable { self.count = count } } + +public struct MemeReactionResponseDTO: Codable { + public let count: Int + + public init(count: Int) { + self.count = count + } +} From 90371f0adfb4576a017b30448614e73ddce19b10 Mon Sep 17 00:00:00 2001 From: chansooo Date: Wed, 2 Oct 2024 00:33:33 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20=EB=B0=98=ED=99=98=EA=B0=92?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20count=20=EB=B0=9B=EC=95=84=EC=84=9C=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PPACData/Sources/Repository/MemeRepositoryImpl.swift | 8 ++++---- .../PPACDomain/Sources/Repository/MemeRepository.swift | 2 +- .../Sources/UseCase/Meme/ReactToMemeUseCase.swift | 4 ++-- .../Features/MemeDetail/Sources/MemeDetailViewModel.swift | 5 ++++- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Projects/Core/PPACData/Sources/Repository/MemeRepositoryImpl.swift b/Projects/Core/PPACData/Sources/Repository/MemeRepositoryImpl.swift index 41079c1..4fe58ae 100644 --- a/Projects/Core/PPACData/Sources/Repository/MemeRepositoryImpl.swift +++ b/Projects/Core/PPACData/Sources/Repository/MemeRepositoryImpl.swift @@ -114,12 +114,12 @@ public class MemeRepositoryImpl: MemeRepository { } } - public func reactToMeme(memeId: String, count: Int) async throws { + public func reactToMeme(memeId: String, count: Int) async throws -> Int { let endpoint = MemeEndpoint.reaction(memeId: memeId, count: count) - let result = await networkservice.request(endpoint, dataType: BaseDTO.self) + let result = await networkservice.request(endpoint, dataType: BaseDTO.self) switch result { - case .success: - return + case .success(let count): + return count.data?.count ?? 0 case .failure(let failure): throw failure } diff --git a/Projects/Core/PPACDomain/Sources/Repository/MemeRepository.swift b/Projects/Core/PPACDomain/Sources/Repository/MemeRepository.swift index 8d880c1..a8b4eed 100644 --- a/Projects/Core/PPACDomain/Sources/Repository/MemeRepository.swift +++ b/Projects/Core/PPACDomain/Sources/Repository/MemeRepository.swift @@ -19,7 +19,7 @@ public protocol MemeRepository { func deleteBookmarkMeme(memeId: String) async throws func shareMeme(memeId: String) async throws func watchMeme(memeId: String, type: String) async throws - func reactToMeme(memeId: String, count: Int) async throws + func reactToMeme(memeId: String, count: Int) async throws -> Int func registerMeme(formData: FormData, title: String, source: String, keywordIds: [String]) async throws } diff --git a/Projects/Core/PPACDomain/Sources/UseCase/Meme/ReactToMemeUseCase.swift b/Projects/Core/PPACDomain/Sources/UseCase/Meme/ReactToMemeUseCase.swift index 26987bf..9208dff 100644 --- a/Projects/Core/PPACDomain/Sources/UseCase/Meme/ReactToMemeUseCase.swift +++ b/Projects/Core/PPACDomain/Sources/UseCase/Meme/ReactToMemeUseCase.swift @@ -10,7 +10,7 @@ import Foundation import PPACModels public protocol ReactToMemeUseCase { - func execute(memeId: String, count: Int) async throws + func execute(memeId: String, count: Int) async throws -> Int } public class ReactToMemeUseCaseImpl: ReactToMemeUseCase { @@ -20,7 +20,7 @@ public class ReactToMemeUseCaseImpl: ReactToMemeUseCase { self.repository = repository } - public func execute(memeId: String, count: Int) async throws { + public func execute(memeId: String, count: Int) async throws -> Int { try await repository.reactToMeme(memeId: memeId, count: count) } } diff --git a/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift b/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift index dc7342a..8397504 100644 --- a/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift +++ b/Projects/Features/MemeDetail/Sources/MemeDetailViewModel.swift @@ -150,7 +150,10 @@ private extension MemeDetailViewModel { } reactionCount = 0 do { - try await reactToMemeUseCase.execute(memeId: state.meme.id, count: count) + 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)") From 066fc54e0155afa9cba8260fcb9204a9cb31317d Mon Sep 17 00:00:00 2001 From: chansooo Date: Wed, 2 Oct 2024 00:44:26 +0900 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20=EB=B0=88=20=EC=83=81=EC=84=B8=20?= =?UTF-8?q?=EB=B0=B0=EA=B2=BD=20=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EB=A7=9E=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MemeDetail/Sources/MemeDetailView.swift | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Projects/Features/MemeDetail/Sources/MemeDetailView.swift b/Projects/Features/MemeDetail/Sources/MemeDetailView.swift index 1a69a52..a96e1c7 100644 --- a/Projects/Features/MemeDetail/Sources/MemeDetailView.swift +++ b/Projects/Features/MemeDetail/Sources/MemeDetailView.swift @@ -40,15 +40,17 @@ public struct MemeDetailView: View { tabBarTap(tab) } .background( - KFImage(URL(string: viewModel.state.meme.imageUrlString)) - .resizable() - .loadDiskFileSynchronously() - .cacheMemoryOnly() - .aspectRatio(contentMode: .fill) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) - .clipped() - .opacity(0.4) - .edgesIgnoringSafeArea(.top) + KFImage(URL(string: viewModel.state.meme.imageUrlString)) + .resizable() + .loadDiskFileSynchronously() + .cacheMemoryOnly() + .aspectRatio(contentMode: .fill) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + .clipped() + .opacity(0.4) // Image Opacity: 40% + .blur(radius: 50) // Layer Blur: 50 + .overlay(Color.white.opacity(0.3)) // White Dim: #fff, Opacity: 30% + .edgesIgnoringSafeArea(.top) ) .onAppear { viewModel.logMemeDetail(interaction: .view, event: .meme)