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 })")