diff --git a/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj b/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj index 8393d2e3..b8b93bb8 100644 --- a/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj +++ b/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj @@ -105,6 +105,7 @@ 3C4993652B4F2471002A99CF /* MyPageSegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4993642B4F2471002A99CF /* MyPageSegmentedControl.swift */; }; 3C4993672B4F2644002A99CF /* MyPageContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4993662B4F2644002A99CF /* MyPageContentViewController.swift */; }; 3C4993692B4F2653002A99CF /* MyPageCommentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4993682B4F2653002A99CF /* MyPageCommentViewController.swift */; }; + 3C4EDCCB2B58653800A9707C /* PostReplyResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4EDCCA2B58653800A9707C /* PostReplyResponseDTO.swift */; }; 3C6192ED2B3A719A00220CEB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C6192EC2B3A719A00220CEB /* AppDelegate.swift */; }; 3C6192EF2B3A719A00220CEB /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C6192EE2B3A719A00220CEB /* SceneDelegate.swift */; }; 3C6192F62B3A719C00220CEB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3C6192F52B3A719C00220CEB /* Assets.xcassets */; }; @@ -138,6 +139,7 @@ 3CF184CB2B4EEC0B00816D5F /* MyPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CF184CA2B4EEC0B00816D5F /* MyPageViewController.swift */; }; 3CF184CD2B4EEC1900816D5F /* MyPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CF184CC2B4EEC1900816D5F /* MyPageView.swift */; }; 3CF184D12B4EFF9900816D5F /* MyPageProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CF184D02B4EFF9900816D5F /* MyPageProfileView.swift */; }; + 3CF4651B2B58398900997FCA /* PostTransparencyRequestDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CF4651A2B58398900997FCA /* PostTransparencyRequestDTO.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -238,6 +240,7 @@ 3C4993642B4F2471002A99CF /* MyPageSegmentedControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageSegmentedControl.swift; sourceTree = ""; }; 3C4993662B4F2644002A99CF /* MyPageContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageContentViewController.swift; sourceTree = ""; }; 3C4993682B4F2653002A99CF /* MyPageCommentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageCommentViewController.swift; sourceTree = ""; }; + 3C4EDCCA2B58653800A9707C /* PostReplyResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostReplyResponseDTO.swift; sourceTree = ""; }; 3C6192E92B3A719A00220CEB /* DontBe-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DontBe-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 3C6192EC2B3A719A00220CEB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 3C6192EE2B3A719A00220CEB /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -273,6 +276,7 @@ 3CF184CA2B4EEC0B00816D5F /* MyPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageViewController.swift; sourceTree = ""; }; 3CF184CC2B4EEC1900816D5F /* MyPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageView.swift; sourceTree = ""; }; 3CF184D02B4EFF9900816D5F /* MyPageProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageProfileView.swift; sourceTree = ""; }; + 3CF4651A2B58398900997FCA /* PostTransparencyRequestDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTransparencyRequestDTO.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -580,6 +584,7 @@ isa = PBXGroup; children = ( 2F05B1A62B5799B700AC368D /* PostDetailResponseDTO.swift */, + 3C4EDCCA2B58653800A9707C /* PostReplyResponseDTO.swift */, ); path = ResponseDTO; sourceTree = ""; @@ -732,6 +737,7 @@ 2FBBADFB2B564471002D6286 /* Home */, 2A28453C2B531DAD0023F9B5 /* SocialLogin */, 3C70BE2A2B53EB81001AA5A6 /* MyPage */, + 3CF465182B58393800997FCA /* Transparency */, 3C61930E2B3A787000220CEB /* Foundation */, ); path = Network; @@ -1042,6 +1048,22 @@ path = ViewControllers; sourceTree = ""; }; + 3CF465182B58393800997FCA /* Transparency */ = { + isa = PBXGroup; + children = ( + 3CF465192B58394E00997FCA /* RequestDTO */, + ); + path = Transparency; + sourceTree = ""; + }; + 3CF465192B58394E00997FCA /* RequestDTO */ = { + isa = PBXGroup; + children = ( + 3CF4651A2B58398900997FCA /* PostTransparencyRequestDTO.swift */, + ); + path = RequestDTO; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -1136,6 +1158,7 @@ 3CBCA3CA2B57212400D348D3 /* MyPageMemberCommentResponseDTO.swift in Sources */, 3CD25D272B5466DB0075F80F /* Empty.swift in Sources */, 2F1741882B500C270089FC4D /* UIApplication+.swift in Sources */, + 3CF4651B2B58398900997FCA /* PostTransparencyRequestDTO.swift in Sources */, 3C2F544E2B50F65500E7BF01 /* DontBeBottomSheetView.swift in Sources */, 2F05B1A72B5799B700AC368D /* PostDetailResponseDTO.swift in Sources */, 3C61930C2B3A782100220CEB /* StringLiterals.swift in Sources */, @@ -1155,6 +1178,7 @@ 2A0A730C2B541A43004478C1 /* NetworkServiceType.swift in Sources */, 3C2F54522B51224500E7BF01 /* MyPageAccountInfoViewController.swift in Sources */, 3CE9C1352B4C4BC20086E4A3 /* CircleProgressbar.swift in Sources */, + 3C4EDCCB2B58653800A9707C /* PostReplyResponseDTO.swift in Sources */, 2AF069B22B518F8E00CA3E48 /* MyPageNicknameEditView.swift in Sources */, 2FB64FF42B531A5C0082A414 /* WriteReplyView.swift in Sources */, 2FBBADF42B53BEB5002D6286 /* TransparentPopupViewController.swift in Sources */, diff --git a/DontBe-iOS/DontBe-iOS/Global/Literals/ImageLiterals.swift b/DontBe-iOS/DontBe-iOS/Global/Literals/ImageLiterals.swift index d595d2ef..bd61b768 100644 --- a/DontBe-iOS/DontBe-iOS/Global/Literals/ImageLiterals.swift +++ b/DontBe-iOS/DontBe-iOS/Global/Literals/ImageLiterals.swift @@ -58,6 +58,7 @@ enum ImageLiterals { enum Home { static var textLogo: UIImage { .load(name: "Logo") } + static var icnNotice: UIImage { .load(name: "icn_notice") } } enum Posting { diff --git a/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift b/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift index c61a7f8a..9a63b6a6 100644 --- a/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift +++ b/DontBe-iOS/DontBe-iOS/Global/Literals/StringLiterals.swift @@ -64,6 +64,7 @@ enum StringLiterals { enum Toast { static let uploading = "게시 중..." static let uploaded = "게시 완료!" + static let alreadyTransparency = "이미 투명도를 적용한 유저예요." } enum Notification { diff --git a/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/Contents.json b/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/Contents.json new file mode 100644 index 00000000..8f14ab35 --- /dev/null +++ b/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "icn_notice.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "icn_notice@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "icn_notice@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/icn_notice.png b/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/icn_notice.png new file mode 100644 index 00000000..a6907403 Binary files /dev/null and b/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/icn_notice.png differ diff --git a/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/icn_notice@2x.png b/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/icn_notice@2x.png new file mode 100644 index 00000000..83d7667c Binary files /dev/null and b/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/icn_notice@2x.png differ diff --git a/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/icn_notice@3x.png b/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/icn_notice@3x.png new file mode 100644 index 00000000..381b5623 Binary files /dev/null and b/DontBe-iOS/DontBe-iOS/Global/Resources/Assets.xcassets/icon/icn_notice.imageset/icn_notice@3x.png differ diff --git a/DontBe-iOS/DontBe-iOS/Network/Post/DTO/ResponseDTO/PostReplyResponseDTO.swift b/DontBe-iOS/DontBe-iOS/Network/Post/DTO/ResponseDTO/PostReplyResponseDTO.swift new file mode 100644 index 00000000..d3409c2a --- /dev/null +++ b/DontBe-iOS/DontBe-iOS/Network/Post/DTO/ResponseDTO/PostReplyResponseDTO.swift @@ -0,0 +1,23 @@ +// +// PostReplyResponseDTO.swift +// DontBe-iOS +// +// Created by 변상우 on 1/18/24. +// + +import Foundation + +// MARK: - PostReplyResponseDTO + +struct PostReplyResponseDTO: Decodable { + let commentId: Int + let memberId: Int + let memberProfileUrl: String + let memberNickname: String + let isGhost: Bool + let memberGhost: Int + let isLiked: Bool + let commentLikedNumber: Int + let commentText: String + let time: String +} diff --git a/DontBe-iOS/DontBe-iOS/Network/Transparency/RequestDTO/PostTransparencyRequestDTO.swift b/DontBe-iOS/DontBe-iOS/Network/Transparency/RequestDTO/PostTransparencyRequestDTO.swift new file mode 100644 index 00000000..e6de3a6b --- /dev/null +++ b/DontBe-iOS/DontBe-iOS/Network/Transparency/RequestDTO/PostTransparencyRequestDTO.swift @@ -0,0 +1,16 @@ +// +// PostTransparencyRequestDTO.swift +// DontBe-iOS +// +// Created by 변상우 on 1/18/24. +// + +import Foundation + +// MARK: - PostTransparencyRequestDTO + +struct PostTransparencyRequestDTO: Encodable { + let alarmTriggerType: String + let targetMemberId: Int + let alarmTriggerId: Int +} diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Home/Cells/HomeCollectionViewCell.swift b/DontBe-iOS/DontBe-iOS/Presentation/Home/Cells/HomeCollectionViewCell.swift index 485fa70d..68fb01ea 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Home/Cells/HomeCollectionViewCell.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Home/Cells/HomeCollectionViewCell.swift @@ -17,6 +17,9 @@ final class HomeCollectionViewCell: UICollectionViewCell, UICollectionViewRegist var LikeButtonAction: (() -> Void) = {} var TransparentButtonAction: (() -> Void) = {} var isLiked: Bool = false + var alarmTriggerType: String = "" + var targetMemberId: Int = 0 + var alarmTriggerdId: Int = 0 // MARK: - UI Components @@ -187,7 +190,7 @@ extension HomeCollectionViewCell { func setLayout() { backgroundUIView.snp.makeConstraints { - $0.edges.equalToSuperview() + $0.top.bottom.equalToSuperview() $0.width.equalTo(UIScreen.main.bounds.width - 32) } diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Home/ViewControllers/HomeViewController.swift b/DontBe-iOS/DontBe-iOS/Presentation/Home/ViewControllers/HomeViewController.swift index ff23262a..a34b6102 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Home/ViewControllers/HomeViewController.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Home/ViewControllers/HomeViewController.swift @@ -29,12 +29,16 @@ final class HomeViewController: UIViewController { let destinationViewController = PostViewController(viewModel: PostViewModel(networkProvider: NetworkService())) var contentId: Int = 0 + var alarmTriggerType: String = "" + var targetMemberId: Int = 0 + var alarmTriggerdId: Int = 0 // MARK: - UI Components private let myView = HomeView() lazy var homeCollectionView = HomeCollectionView().collectionView private var uploadToastView: DontBeToastView? + private var alreadyTransparencyToastView: DontBeToastView? // MARK: - Life Cycles @@ -135,6 +139,7 @@ extension HomeViewController { private func setDelegate() { homeCollectionView.dataSource = self homeCollectionView.delegate = self + transparentPopupVC.transparentButtonPopupView.delegate = self } private func setNotification() { @@ -210,6 +215,33 @@ extension HomeViewController { } } } + + func showAlreadyTransparencyToast() { + DispatchQueue.main.async { + self.alreadyTransparencyToastView = DontBeToastView() + self.alreadyTransparencyToastView?.toastLabel.text = StringLiterals.Toast.alreadyTransparency + self.alreadyTransparencyToastView?.circleProgressBar.alpha = 0 + self.alreadyTransparencyToastView?.checkImageView.alpha = 1 + self.alreadyTransparencyToastView?.checkImageView.image = ImageLiterals.Home.icnNotice + self.alreadyTransparencyToastView?.container.backgroundColor = .donPrimary + + self.view.addSubviews(self.alreadyTransparencyToastView ?? DontBeToastView()) + + self.alreadyTransparencyToastView?.snp.makeConstraints { + $0.leading.trailing.equalToSuperview().inset(16.adjusted) + $0.bottom.equalTo(self.tabBarHeight.adjusted).inset(6.adjusted) + $0.height.equalTo(44.adjusted) + } + + UIView.animate(withDuration: 1.5, delay: 1, options: .curveEaseIn) { + self.alreadyTransparencyToastView?.alpha = 0 + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) { + self.alreadyTransparencyToastView?.removeFromSuperview() + } + } + } } // MARK: - Network @@ -246,25 +278,27 @@ extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelega func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = HomeCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) + cell.alarmTriggerType = "contentGhost" + cell.targetMemberId = viewModel.postData[indexPath.row].memberId + cell.alarmTriggerdId = viewModel.postData[indexPath.row].contentId if viewModel.postData[indexPath.row].memberId == loadUserData()?.memberId { cell.ghostButton.isHidden = true cell.verticalTextBarView.isHidden = true - cell.KebabButtonAction = { - self.deleteBottomsheet.showSettings() - } } else { cell.ghostButton.isHidden = false cell.verticalTextBarView.isHidden = false - cell.KebabButtonAction = { - self.deleteBottomsheet.showSettings() - } + } + cell.KebabButtonAction = { + self.deleteBottomsheet.showSettings() } cell.LikeButtonAction = { cell.isLiked.toggle() cell.likeButton.setImage(cell.isLiked ? ImageLiterals.Posting.btnFavoriteActive : ImageLiterals.Posting.btnFavoriteInActive, for: .normal) } cell.TransparentButtonAction = { - // present + self.alarmTriggerType = cell.alarmTriggerType + self.targetMemberId = cell.targetMemberId + self.alarmTriggerdId = cell.alarmTriggerdId self.present(self.transparentPopupVC, animated: false, completion: nil) } cell.nicknameLabel.text = viewModel.postData[indexPath.row].memberNickname @@ -295,3 +329,29 @@ extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelega return CGSize(width: UIScreen.main.bounds.width, height: 24.adjusted) } } + +extension HomeViewController: DontBePopupDelegate { + func cancleButtonTapped() { + self.dismiss(animated: false) + } + + func confirmButtonTapped() { + self.dismiss(animated: false) + Task { + do { + if let accessToken = KeychainWrapper.loadToken(forKey: "accessToken") { + let result = try await self.viewModel.postDownTransparency(accessToken: accessToken, + alarmTriggerType: self.alarmTriggerType, + targetMemberId: self.targetMemberId, + alarmTriggerId: self.alarmTriggerdId) + if result?.status == 400 { + // 이미 투명도를 누른 대상인 경우, 토스트 메시지 보여주기 + showAlreadyTransparencyToast() + } + } + } catch { + print(error) + } + } + } +} diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Home/ViewModel/HomeViewModel.swift b/DontBe-iOS/DontBe-iOS/Presentation/Home/ViewModel/HomeViewModel.swift index 7be07f58..edc4deae 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Home/ViewModel/HomeViewModel.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Home/ViewModel/HomeViewModel.swift @@ -62,10 +62,13 @@ final class HomeViewModel: ViewModelType { extension HomeViewModel { private func getPostDataAPI(accessToken: String) async throws -> BaseResponse<[PostDataResponseDTO]>? { - let accessToken = accessToken do { - let result: BaseResponse<[PostDataResponseDTO]>? = try - await self.networkProvider.donNetwork(type: .get, baseURL: Config.baseURL + "/content/all", accessToken: accessToken, body: EmptyBody(), pathVariables: ["":""]) + let result: BaseResponse<[PostDataResponseDTO]>? = try await + self.networkProvider.donNetwork(type: .get, + baseURL: Config.baseURL + "/content/all", + accessToken: accessToken, + body: EmptyBody(), + pathVariables: ["":""]) if let data = result?.data { var tempArrayData: [PostDataResponseDTO] = [] @@ -80,4 +83,22 @@ extension HomeViewModel { return nil } } + + func postDownTransparency(accessToken: String, alarmTriggerType: String, targetMemberId: Int, alarmTriggerId: Int) async throws -> BaseResponse? { + do { + let result: BaseResponse? = try await + self.networkProvider.donNetwork(type: .post, + baseURL: Config.baseURL + "/ghost", + accessToken: accessToken, + body: PostTransparencyRequestDTO( + alarmTriggerType: alarmTriggerType, + targetMemberId: targetMemberId, + alarmTriggerId: alarmTriggerId + ), + pathVariables: ["":""]) + return result + } catch { + return nil + } + } } diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Post/Cells/PostReplyCollectionViewCell.swift b/DontBe-iOS/DontBe-iOS/Presentation/Post/Cells/PostReplyCollectionViewCell.swift index d7dd017f..c5b32ef3 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Post/Cells/PostReplyCollectionViewCell.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Post/Cells/PostReplyCollectionViewCell.swift @@ -17,6 +17,9 @@ final class PostReplyCollectionViewCell: UICollectionViewCell, UICollectionViewR var LikeButtonAction: (() -> Void) = {} var TransparentButtonAction: (() -> Void) = {} var isLiked: Bool = false + var alarmTriggerType: String = "" + var targetMemberId: Int = 0 + var alarmTriggerdId: Int = 0 // MARK: - UI Components @@ -27,7 +30,7 @@ final class PostReplyCollectionViewCell: UICollectionViewCell, UICollectionViewR return view }() - private let profileImageView: UIImageView = { + let profileImageView: UIImageView = { let image = UIImageView() image.contentMode = .scaleAspectFill image.clipsToBounds = true @@ -36,7 +39,7 @@ final class PostReplyCollectionViewCell: UICollectionViewCell, UICollectionViewR return image }() - private let nicknameLabel: UILabel = { + let nicknameLabel: UILabel = { let label = UILabel() label.textColor = .donBlack label.text = "Don't be야 사랑해~" @@ -44,7 +47,7 @@ final class PostReplyCollectionViewCell: UICollectionViewCell, UICollectionViewR return label }() - private let transparentLabel: UILabel = { + let transparentLabel: UILabel = { let label = UILabel() label.textColor = .donGray9 label.text = "투명도 0%" @@ -60,7 +63,7 @@ final class PostReplyCollectionViewCell: UICollectionViewCell, UICollectionViewR return label }() - private let timeLabel: UILabel = { + let timeLabel: UILabel = { let label = UILabel() label.textColor = .donGray9 label.text = "3분 전" @@ -68,13 +71,13 @@ final class PostReplyCollectionViewCell: UICollectionViewCell, UICollectionViewR return label }() - private let kebabButton: UIButton = { + let kebabButton: UIButton = { let button = UIButton() button.setImage(ImageLiterals.Posting.btnKebab, for: .normal) return button }() - private let contentTextLabel: UILabel = { + let contentTextLabel: UILabel = { let label = UILabel() label.textColor = .donBlack label.text = "돈비를 사용하면 진짜 돈비를 맞을 수 있나요? 저 돈비 맞고 싶어요 돈벼락이 최고입니다. 돈비를 사용하면 진짜 돈비를 맞을 수 있나요? 저 돈비 맞고 싶어요 돈벼락이 최고입니다." @@ -98,7 +101,7 @@ final class PostReplyCollectionViewCell: UICollectionViewCell, UICollectionViewR return button }() - private let likeNumLabel: UILabel = { + let likeNumLabel: UILabel = { let label = UILabel() label.textColor = .donGray11 label.text = "54" @@ -106,13 +109,13 @@ final class PostReplyCollectionViewCell: UICollectionViewCell, UICollectionViewR return label }() - private let ghostButton: UIButton = { + let ghostButton: UIButton = { let button = UIButton() button.setImage(ImageLiterals.Posting.btnTransparent, for: .normal) return button }() - private let verticalTextBarView: UIView = { + let verticalTextBarView: UIView = { let view = UIView() view.backgroundColor = .donPale return view diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewControllers/PostViewController.swift b/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewControllers/PostViewController.swift index 38632c3d..068aacc6 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewControllers/PostViewController.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewControllers/PostViewController.swift @@ -23,6 +23,10 @@ final class PostViewController: UIViewController { private var cancelBag = CancelBag() var contentId: Int = 0 + var memberId: Int = 0 + var alarmTriggerType: String = "" + var targetMemberId: Int = 0 + var alarmTriggerdId: Int = 0 // MARK: - UI Components @@ -32,6 +36,7 @@ final class PostViewController: UIViewController { private lazy var postReplyCollectionView = PostReplyCollectionView().collectionView private lazy var greenTextField = textFieldView.greenTextFieldView private var uploadToastView: DontBeToastView? + private var alreadyTransparencyToastView: DontBeToastView? private let verticalBarView: UIView = { let view = UIView() @@ -45,8 +50,6 @@ final class PostViewController: UIViewController { super.loadView() view = myView - self.navigationController?.navigationBar.isHidden = false - textFieldView.isUserInteractionEnabled = true } override func viewDidLoad() { @@ -83,6 +86,8 @@ final class PostViewController: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationItem.hidesBackButton = true + self.navigationItem.title = StringLiterals.Post.navigationTitleLabel + self.navigationController?.navigationBar.isHidden = false self.navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.donBlack] let backButton = UIBarButtonItem.backButton(target: self, action: #selector(backButtonPressed)) @@ -96,11 +101,9 @@ final class PostViewController: UIViewController { extension PostViewController { private func setUI() { - self.navigationItem.title = StringLiterals.Post.navigationTitleLabel - textFieldView.replyTextFieldLabel.text = (postUserNickname ?? "") + StringLiterals.Post.textFieldLabel - self.view.backgroundColor = .donWhite - + textFieldView.isUserInteractionEnabled = true + textFieldView.replyTextFieldLabel.text = (postUserNickname ?? "") + StringLiterals.Post.textFieldLabel transparentPopupVC.modalPresentationStyle = .overFullScreen deletePostPopupVC.modalPresentationStyle = .overFullScreen } @@ -142,6 +145,7 @@ extension PostViewController { private func setDelegate() { postReplyCollectionView.dataSource = self postReplyCollectionView.delegate = self + transparentPopupVC.transparentButtonPopupView.delegate = self NotificationCenter.default.addObserver(self, selector: #selector(dismissViewController), name: CancelReplyPopupViewController.popViewController, object: nil) } @@ -199,6 +203,33 @@ extension PostViewController { } } + func showAlreadyTransparencyToast() { + DispatchQueue.main.async { + self.alreadyTransparencyToastView = DontBeToastView() + self.alreadyTransparencyToastView?.toastLabel.text = StringLiterals.Toast.alreadyTransparency + self.alreadyTransparencyToastView?.circleProgressBar.alpha = 0 + self.alreadyTransparencyToastView?.checkImageView.alpha = 1 + self.alreadyTransparencyToastView?.checkImageView.image = ImageLiterals.Home.icnNotice + self.alreadyTransparencyToastView?.container.backgroundColor = .donPrimary + + self.view.addSubviews(self.alreadyTransparencyToastView ?? DontBeToastView()) + + self.alreadyTransparencyToastView?.snp.makeConstraints { + $0.leading.trailing.equalToSuperview().inset(16.adjusted) + $0.bottom.equalTo(self.tabBarHeight.adjusted).inset(6.adjusted) + $0.height.equalTo(44) + } + + UIView.animate(withDuration: 1.5, delay: 1, options: .curveEaseIn) { + self.alreadyTransparencyToastView?.alpha = 0 + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) { + self.alreadyTransparencyToastView?.removeFromSuperview() + } + } + } + @objc private func backButtonPressed() { self.navigationController?.popViewController(animated: true) @@ -239,6 +270,9 @@ extension PostViewController { @objc func transparentShowPopupButton() { + self.alarmTriggerType = "contentGhost" + self.targetMemberId = self.memberId + self.alarmTriggerdId = self.contentId self.present(self.transparentPopupVC, animated: false, completion: nil) } @@ -271,16 +305,24 @@ extension PostViewController { extension PostViewController { private func getAPI() { - let input = PostViewModel.Input(viewUpdate: Just((contentId)).eraseToAnyPublisher()) + let input = PostViewModel.Input(viewUpdate: Just((contentId)).eraseToAnyPublisher(), collectionViewUpdata: Just((contentId)).eraseToAnyPublisher()) let output = viewModel.transform(from: input, cancelBag: cancelBag) output.getPostData .receive(on: RunLoop.main) .sink { data in + print(data) self.bindPostData(data: data) } .store(in: self.cancelBag) + + output.getPostReplyData + .receive(on: RunLoop.main) + .sink { data in + self.postReplyCollectionView.reloadData() + } + .store(in: self.cancelBag) } private func bindPostData(data: PostDetailResponseDTO) { @@ -290,6 +332,15 @@ extension PostViewController { self.postView.timeLabel.text = data.time.formattedTime() self.postView.likeNumLabel.text = "\(data.likedNumber)" self.postView.commentNumLabel.text = "\(data.commentNumber)" + self.memberId = data.memberId + + if self.memberId == loadUserData()?.memberId { + self.postView.ghostButton.isHidden = true + self.postView.verticalTextBarView.isHidden = true + } else { + self.postView.ghostButton.isHidden = false + self.postView.verticalTextBarView.isHidden = false + } } } @@ -297,24 +348,47 @@ extension PostViewController: UICollectionViewDelegate { } extension PostViewController: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - 5 + let sortedData = viewModel.postReplyData.sorted { + $0.time.compare($1.time, options: .numeric) == .orderedDescending + } + + viewModel.postReplyData = sortedData + return viewModel.postReplyData.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = PostReplyCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) - + cell.alarmTriggerType = "commentGhost" + cell.targetMemberId = viewModel.postReplyData[indexPath.row].memberId + cell.alarmTriggerdId = self.contentId + if viewModel.postReplyData[indexPath.row].memberId == loadUserData()?.memberId { + cell.ghostButton.isHidden = true + cell.verticalTextBarView.isHidden = true + } else { + cell.ghostButton.isHidden = false + cell.verticalTextBarView.isHidden = false + } cell.KebabButtonAction = { - self.deleteBottomsheet.showSettings() - } - cell.LikeButtonAction = { - cell.isLiked.toggle() - cell.likeButton.setImage(cell.isLiked ? ImageLiterals.Posting.btnFavoriteActive : ImageLiterals.Posting.btnFavoriteInActive, for: .normal) - } - cell.TransparentButtonAction = { - // present - self.present(self.transparentPopupVC, animated: false, completion: nil) - } + self.deleteBottomsheet.showSettings() + } + cell.LikeButtonAction = { + cell.isLiked.toggle() + cell.likeButton.setImage(cell.isLiked ? ImageLiterals.Posting.btnFavoriteActive : ImageLiterals.Posting.btnFavoriteInActive, for: .normal) + } + cell.TransparentButtonAction = { + self.alarmTriggerType = cell.alarmTriggerType + self.targetMemberId = cell.targetMemberId + self.alarmTriggerdId = cell.alarmTriggerdId + self.present(self.transparentPopupVC, animated: false, completion: nil) + } + cell.nicknameLabel.text = viewModel.postReplyData[indexPath.row].memberNickname + cell.transparentLabel.text = "투명도 \(viewModel.postReplyData[indexPath.row].memberGhost)%" + cell.contentTextLabel.text = viewModel.postReplyData[indexPath.row].commentText + cell.likeNumLabel.text = "\(viewModel.postReplyData[indexPath.row].commentLikedNumber)" + cell.timeLabel.text = "\(viewModel.postReplyData[indexPath.row].time.formattedTime())" + cell.profileImageView.load(url: "\(viewModel.postReplyData[indexPath.row].memberProfileUrl)") + return cell } @@ -330,3 +404,29 @@ extension PostViewController: UICollectionViewDataSource { return CGSize(width: UIScreen.main.bounds.width, height: 24.adjusted) } } + +extension PostViewController: DontBePopupDelegate { + func cancleButtonTapped() { + self.dismiss(animated: false) + } + + func confirmButtonTapped() { + self.dismiss(animated: false) + Task { + do { + if let accessToken = KeychainWrapper.loadToken(forKey: "accessToken") { + let result = try await self.viewModel.postDownTransparency(accessToken: accessToken, + alarmTriggerType: self.alarmTriggerType, + targetMemberId: self.targetMemberId, + alarmTriggerId: self.alarmTriggerdId) + if result?.status == 400 { + // 이미 투명도를 누른 대상인 경우, 토스트 메시지 보여주기 + showAlreadyTransparencyToast() + } + } + } catch { + print(error) + } + } + } +} diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewControllers/TransparentPopupViewController.swift b/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewControllers/TransparentPopupViewController.swift index f6c4625c..ac637702 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewControllers/TransparentPopupViewController.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewControllers/TransparentPopupViewController.swift @@ -13,7 +13,7 @@ final class TransparentPopupViewController: UIViewController { // MARK: - UI Components - private let transparentButtonPopupView = DontBePopupView(popupImage: ImageLiterals.Popup.transparentButtonImage, + let transparentButtonPopupView = DontBePopupView(popupImage: ImageLiterals.Popup.transparentButtonImage, popupTitle: StringLiterals.Home.transparentPopupTitleLabel, popupContent: StringLiterals.Home.transparentPopupContentLabel, leftButtonTitle: StringLiterals.Home.transparentPopupLefteftButtonTitle, @@ -58,7 +58,7 @@ extension TransparentPopupViewController { } private func setDelegate() { - transparentButtonPopupView.delegate = self + } } @@ -69,14 +69,3 @@ extension TransparentPopupViewController { } } - -extension TransparentPopupViewController: DontBePopupDelegate { - func cancleButtonTapped() { - self.dismiss(animated: false) - } - - func confirmButtonTapped() { - self.dismiss(animated: false) - // ✅ 투명도 주기 버튼 클릭 시 액션 추가 - } -} diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewModel/PostViewModel.swift b/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewModel/PostViewModel.swift index 29a96c74..3857737b 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewModel/PostViewModel.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Post/ViewModel/PostViewModel.swift @@ -13,15 +13,19 @@ final class PostViewModel: ViewModelType { private let cancelBag = CancelBag() private let networkProvider: NetworkServiceType private var getPostData = PassthroughSubject() + private var getPostReplyData = PassthroughSubject<[PostReplyResponseDTO], Never>() var postDetailData: [String] = [] + var postReplyData: [PostReplyResponseDTO] = [] struct Input { let viewUpdate: AnyPublisher + let collectionViewUpdata: AnyPublisher } struct Output { let getPostData: PassthroughSubject + let getPostReplyData: PassthroughSubject<[PostReplyResponseDTO], Never> } func transform(from input: Input, cancelBag: CancelBag) -> Output { @@ -42,7 +46,27 @@ final class PostViewModel: ViewModelType { } } .store(in: self.cancelBag) - return Output(getPostData: getPostData) + + input.collectionViewUpdata + .sink { value in + Task { + do { + if let accessToken = KeychainWrapper.loadToken(forKey: "accessToken") { + let postReplyResult = try await + self.getPostReplyDataAPI(accessToken: accessToken, contentId: value) + if let data = postReplyResult?.data { + self.postReplyData = data + self.getPostReplyData.send(data) + } + } + } catch { + print(error) + } + } + } + .store(in: self.cancelBag) + + return Output(getPostData: getPostData, getPostReplyData: getPostReplyData) } init(networkProvider: NetworkServiceType) { @@ -56,11 +80,41 @@ final class PostViewModel: ViewModelType { extension PostViewModel { private func getPostDetailDataAPI(accessToken: String, contentId: Int) async throws -> BaseResponse? { - let accessToken = accessToken do { let result: BaseResponse? = try await self.networkProvider.donNetwork(type: .get, baseURL: Config.baseURL + "/content/\(contentId)/detail", accessToken: accessToken, body: EmptyBody(), pathVariables: ["":""]) - + return result + } catch { + return nil + } + } + + private func getPostReplyDataAPI(accessToken: String, contentId: Int) async throws -> BaseResponse<[PostReplyResponseDTO]>? { + do { + let result: BaseResponse<[PostReplyResponseDTO]>? = try await + self.networkProvider.donNetwork(type: .get, + baseURL: Config.baseURL + "/content/\(contentId)/comment/all", + accessToken: accessToken, + body: EmptyBody(), + pathVariables: ["":""]) + return result + } catch { + return nil + } + } + + func postDownTransparency(accessToken: String, alarmTriggerType: String, targetMemberId: Int, alarmTriggerId: Int) async throws -> BaseResponse? { + do { + let result: BaseResponse? = try await + self.networkProvider.donNetwork(type: .post, + baseURL: Config.baseURL + "/ghost", + accessToken: accessToken, + body: PostTransparencyRequestDTO( + alarmTriggerType: alarmTriggerType, + targetMemberId: targetMemberId, + alarmTriggerId: alarmTriggerId + ), + pathVariables: ["":""]) return result } catch { return nil diff --git a/DontBe-iOS/DontBe-iOS/Presentation/TabBar/DontBeTabBarController.swift b/DontBe-iOS/DontBe-iOS/Presentation/TabBar/DontBeTabBarController.swift index 534155f6..5f344f77 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/TabBar/DontBeTabBarController.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/TabBar/DontBeTabBarController.swift @@ -11,6 +11,8 @@ final class DontBeTabBarController: UITabBarController { private let networkProvider = NetworkService() + var beforeIndex: Int = 0 + // MARK: - Life Cycle override func viewDidLoad() { @@ -148,7 +150,7 @@ extension DontBeTabBarController: UITabBarControllerDelegate { func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { if selectedIndex == 1 { - self.selectedIndex = 0 + self.selectedIndex = beforeIndex } if selectedIndex == 2 { @@ -166,6 +168,7 @@ extension DontBeTabBarController: UITabBarControllerDelegate { } } } + beforeIndex = self.selectedIndex } func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool { diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Write/ViewControllers/WriteViewController.swift b/DontBe-iOS/DontBe-iOS/Presentation/Write/ViewControllers/WriteViewController.swift index 60a9acb7..dd93773a 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Write/ViewControllers/WriteViewController.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Write/ViewControllers/WriteViewController.swift @@ -57,6 +57,13 @@ final class WriteViewController: UIViewController { self.navigationController?.navigationBar.isHidden = false self.navigationItem.hidesBackButton = false } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(true) + + self.navigationController?.navigationBar.isHidden = true + self.navigationItem.hidesBackButton = true + } } // MARK: - Extensions @@ -81,6 +88,8 @@ extension WriteViewController { ], for: .normal) navigationItem.leftBarButtonItem = backButton + + self.rootView.writeTextView.userNickname.text = loadUserData()?.userNickname } private func setDelegate() { diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Write/Views/WriteTextView.swift b/DontBe-iOS/DontBe-iOS/Presentation/Write/Views/WriteTextView.swift index c6255b0c..c1591665 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Write/Views/WriteTextView.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Write/Views/WriteTextView.swift @@ -18,15 +18,14 @@ final class WriteTextView: UIView { // MARK: - UI Components - private let userProfileImage: UIImageView = { + let userProfileImage: UIImageView = { let imageView = UIImageView() imageView.load(url: StringLiterals.Network.baseImageURL) return imageView }() - private let userNickname: UILabel = { + let userNickname: UILabel = { let label = UILabel() - label.text = "뚜비요" label.font = UIFont.font(.body1) label.textColor = .donBlack return label