diff --git a/14th-team5-iOS/App/Sources/Presentation/Home/Reactor/HomeViewReactor.swift b/14th-team5-iOS/App/Sources/Presentation/Home/Reactor/HomeViewReactor.swift index ed0db8af7..7ee3bf3ab 100644 --- a/14th-team5-iOS/App/Sources/Presentation/Home/Reactor/HomeViewReactor.swift +++ b/14th-team5-iOS/App/Sources/Presentation/Home/Reactor/HomeViewReactor.swift @@ -22,7 +22,7 @@ public final class HomeViewReactor: Reactor { case setLoading(Bool) case setDidPost case setDescriptionText(String) - case showNoPostTodayView + case showNoPostTodayView(Bool) case setPostCollectionView([SectionModel]) case setRefreshing(Bool) } @@ -54,10 +54,12 @@ extension HomeViewReactor { .flatMap { postList in guard let postList, !postList.postLists.isEmpty else { - return Observable.just(Mutation.showNoPostTodayView) + return Observable.just(Mutation.showNoPostTodayView(true)) } - var observables = [Observable.just(Mutation.setPostCollectionView([ + var observables = [ + Observable.just(Mutation.showNoPostTodayView(false)), + Observable.just(Mutation.setPostCollectionView([ SectionModel(model: "section1", items: postList.postLists)]))] if postList.selfUploaded { @@ -81,8 +83,8 @@ extension HomeViewReactor { var newState = state switch mutation { - case .showNoPostTodayView: - newState.isShowingNoPostTodayView = true + case let .showNoPostTodayView(isShow): + newState.isShowingNoPostTodayView = isShow case let .setPostCollectionView(data): newState.feedSections = data case .setDidPost: diff --git a/14th-team5-iOS/App/Sources/Presentation/Home/ViewControllers/HomeViewController.swift b/14th-team5-iOS/App/Sources/Presentation/Home/ViewControllers/HomeViewController.swift index 3b35f13a1..3462095c6 100644 --- a/14th-team5-iOS/App/Sources/Presentation/Home/ViewControllers/HomeViewController.swift +++ b/14th-team5-iOS/App/Sources/Presentation/Home/ViewControllers/HomeViewController.swift @@ -293,12 +293,8 @@ public final class HomeViewController: BaseViewController { extension HomeViewController { private func setNoPostTodayView(_ isShow: Bool) { - if isShow { - noPostTodayView.isHidden = !isShow - postCollectionView.isHidden = isShow - } else { - noPostTodayView.isHidden = !isShow - } + noPostTodayView.isHidden = !isShow + postCollectionView.isHidden = isShow } private func hideCameraButton(_ isShow: Bool) { diff --git a/14th-team5-iOS/App/Sources/Presentation/Home/Views/FamilyCollectionViewCell.swift b/14th-team5-iOS/App/Sources/Presentation/Home/Views/FamilyCollectionViewCell.swift index cf1a7337f..fa691a832 100644 --- a/14th-team5-iOS/App/Sources/Presentation/Home/Views/FamilyCollectionViewCell.swift +++ b/14th-team5-iOS/App/Sources/Presentation/Home/Views/FamilyCollectionViewCell.swift @@ -10,9 +10,12 @@ import Core import Domain final class FamilyCollectionViewCell: BaseCollectionViewCell { + typealias Layout = HomeAutoLayout.ProfileView static let id: String = "familyCollectionViewCell" - - private let profileView = ProfileView() + + private let defaultNameLabel = BibbiLabel(.head1, alignment: .center, textColor: .gray200) + private let imageView = UIImageView() + private let nameLabel = UILabel() override init(frame: CGRect) { super.init(frame: frame) @@ -25,22 +28,63 @@ final class FamilyCollectionViewCell: BaseCollectionViewCell { override func bind(reactor: HomeViewReactor) { } override func setupUI() { - addSubview(profileView) + addSubviews(imageView, nameLabel, defaultNameLabel) } override func setupAutoLayout() { - profileView.snp.makeConstraints { - $0.edges.equalToSuperview() + imageView.snp.makeConstraints { + $0.horizontalEdges.equalToSuperview() + $0.width.height.equalTo(64) + $0.top.leading.equalToSuperview() + } + + nameLabel.snp.makeConstraints { + $0.top.equalTo(imageView.snp.bottom).offset(Layout.NameLabel.topOffset) + $0.horizontalEdges.equalToSuperview() + $0.bottom.equalToSuperview() + } + + defaultNameLabel.snp.makeConstraints { + $0.center.equalTo(imageView) } } override func setupAttributes() { + nameLabel.do { + $0.font = UIFont.pretendard(.caption) + $0.textAlignment = .center + $0.textColor = .gray300 + + $0.numberOfLines = 1 + $0.lineBreakMode = .byTruncatingTail + } + imageView.do { + $0.clipsToBounds = true + $0.contentMode = .scaleAspectFill + $0.layer.cornerRadius = 64 / 2 + } + } + + override func prepareForReuse() { + imageView.image = nil } } extension FamilyCollectionViewCell { func setCell(data: ProfileData) { - profileView.setProfile(profile: data) + if let profileImageURL = data.profileImageURL, + let url = URL(string: profileImageURL), !profileImageURL.isEmpty { + imageView.kf.setImage(with: url) + defaultNameLabel.isHidden = true + } else { + guard let name = data.name.first else { + return + } + defaultNameLabel.isHidden = false + imageView.backgroundColor = .gray800 + defaultNameLabel.text = "\(name)" + } + nameLabel.text = data.name } } diff --git a/14th-team5-iOS/App/Sources/Presentation/PostDetail/Reactor/EmojiReactor.swift b/14th-team5-iOS/App/Sources/Presentation/PostDetail/Reactor/EmojiReactor.swift index b6a7b5148..4c17d60b1 100644 --- a/14th-team5-iOS/App/Sources/Presentation/PostDetail/Reactor/EmojiReactor.swift +++ b/14th-team5-iOS/App/Sources/Presentation/PostDetail/Reactor/EmojiReactor.swift @@ -114,7 +114,7 @@ extension EmojiReactor { var newState = state switch mutation { case .showSelectableEmojiStackView: - newState.isShowingSelectableEmojiStackView.toggle() + newState.isShowingSelectableEmojiStackView = true case let .selectEmoji(emoji): guard let myMemberId = UserDefaults.standard.memberId, let fetchedEmojiList = newState.fetchedEmojiList else { diff --git a/14th-team5-iOS/App/Sources/Presentation/PostDetail/ViewControllers/PostViewController.swift b/14th-team5-iOS/App/Sources/Presentation/PostDetail/ViewControllers/PostViewController.swift index 36b106854..5e6484f30 100644 --- a/14th-team5-iOS/App/Sources/Presentation/PostDetail/ViewControllers/PostViewController.swift +++ b/14th-team5-iOS/App/Sources/Presentation/PostDetail/ViewControllers/PostViewController.swift @@ -12,7 +12,6 @@ import Domain import RxDataSources import RxSwift -// index 조회 필요 => index 조회 이후 스크롤시 이전/이후 포스트 조회 할 수 있어야함 final class PostViewController: BaseViewController { private let backgroundImageView: UIImageView = UIImageView() private let blurEffectView: UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffect.Style.dark)) @@ -46,20 +45,14 @@ final class PostViewController: BaseViewController { .map { $0.selectedPost } .withUnretained(self) .observe(on: MainScheduler.instance) - .bind(onNext: { - $0.0.setBackgroundView(data: $0.1) - }) + .bind(onNext: { $0.0.setBackgroundView(data: $0.1) }) .disposed(by: disposeBag) reactor.state .map { $0.reactionMemberIds } - .asObservable() - .distinctUntilChanged() .withUnretained(self) .observe(on: MainScheduler.instance) - .bind(onNext: { - $0.0.showReactionSheet($0.1) - }) + .subscribe(onNext: { $0.0.showReactionSheet($0.1) }) .disposed(by: disposeBag) reactor.state @@ -162,6 +155,7 @@ extension PostViewController { private func showReactionSheet(_ memberIds: [String]) { if memberIds.isEmpty { return } + let reactionMembersViewController = ReactionDIContainer().makeViewController(memberIds: memberIds) if let sheet = reactionMembersViewController.sheetPresentationController { sheet.detents = [.medium()] diff --git a/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/EmojiCountButton.swift b/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/EmojiCountButton.swift index 0c13d59d4..fa26a1c3d 100644 --- a/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/EmojiCountButton.swift +++ b/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/EmojiCountButton.swift @@ -16,26 +16,28 @@ import RxCocoa final class EmojiCountButton: BaseView { typealias Layout = PostAutoLayout.CollectionView.CollectionViewCell.EmojiCountStackView.EmojiCountButton + private enum GestureType { + case tap + case longPress + } + private let emojiImageView = UIImageView() private let countLabel = BibbiLabel(.body1Regular, alignment: .right) + private let tapGesture = UITapGestureRecognizer() + private let longPressGesture = UILongPressGestureRecognizer() - var isSelected: Bool = false { - didSet { - if isSelected { - setSelected() - } else { - setUnSelected() - } - } - } + let selectedRelay: BehaviorRelay = BehaviorRelay(value: false) convenience init(reactor: Reactor) { self.init(frame: .zero) self.reactor = reactor } - + override init(frame: CGRect) { super.init(frame: frame) + + self.addGestureRecognizer(tapGesture) + self.addGestureRecognizer(longPressGesture) } required init?(coder: NSCoder) { @@ -43,16 +45,29 @@ final class EmojiCountButton: BaseView { } override func bind(reactor: EmojiReactor) { - self.rx.tap + tapGesture.rx.event .throttle(RxConst.throttleInterval, scheduler: MainScheduler.instance) - .map { Reactor.Action.tappedSelectedEmojiCountButton(Emojis.emoji(forIndex: self.tag)) } + .map { _ in Reactor.Action.tappedSelectedEmojiCountButton(Emojis.emoji(forIndex: self.tag)) } .bind(to: reactor.action) .disposed(by: disposeBag) - self.rx.longPress + longPressGesture.rx.event .map { _ in Reactor.Action.longPressedEmojiCountButton(self.tag) } .bind(to: reactor.action) .disposed(by: disposeBag) + + longPressGesture.rx.event + .asObservable() + .map { $0.state } + .withUnretained(self) { ($0, $1) } + .bind(onNext: { $0.0.tapGesture.isEnabled = $0.1 == .ended }) + .disposed(by: disposeBag) + + selectedRelay + .withUnretained(self) + .observe(on: MainScheduler.instance) + .bind(onNext: { $0.0.setSelected($0.1) }) + .disposed(by: disposeBag) } override func setupUI() { @@ -81,14 +96,12 @@ final class EmojiCountButton: BaseView { } extension EmojiCountButton { - private func setUnSelected() { - backgroundColor = UIColor(red: 0.141, green: 0.141, blue: 0.153, alpha: 0.5) - layer.borderWidth = 0 - } - - private func setSelected() { - backgroundColor = UIColor(red: 0.141, green: 0.141, blue: 0.153, alpha: 1) - layer.borderWidth = 1 + private func setSelected(_ isSelected: Bool) { + let alpha = isSelected ? 1: 0.5 + let borderWidth: CGFloat = isSelected ? 1 : 0 + + backgroundColor = UIColor(red: 0.141, green: 0.141, blue: 0.153, alpha: alpha) + layer.borderWidth = borderWidth layer.borderColor = UIColor(red: 0.908, green: 0.908, blue: 0.908, alpha: 1).cgColor } } @@ -98,8 +111,4 @@ extension EmojiCountButton { emojiImageView.image = emoji.emoji.emojiImage countLabel.text = "\(emoji.count)" } - - func setCountLabel(_ count: Int) { - countLabel.text = "\(count)" - } } diff --git a/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/PostCollectionViewCell.swift b/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/PostCollectionViewCell.swift index 6191c3a8c..4a8f3f564 100644 --- a/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/PostCollectionViewCell.swift +++ b/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/PostCollectionViewCell.swift @@ -59,6 +59,11 @@ final class PostCollectionViewCell: BaseCollectionViewCell { postImageView.image = nil } + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + super.touchesBegan(touches, with: event) + selectableEmojiStackView.isHidden = true + } + override func bind(reactor: EmojiReactor) { reactionButtons.enumerated().forEach { index, button in button.rx.tap @@ -87,7 +92,7 @@ final class PostCollectionViewCell: BaseCollectionViewCell { reactor.state .map { $0.isShowingSelectableEmojiStackView } - .distinctUntilChanged() + .filter { $0 } .withUnretained(self) .bind(onNext: { $0.0.showSelectableEmojiStackView($0.1) @@ -296,7 +301,7 @@ extension PostCollectionViewCell { let emojiCountButton = EmojiCountButton(reactor: reactor) emojiCountButton.tag = index + 1 - emojiCountButton.isSelected = emojiData.isSelfSelected + emojiCountButton.selectedRelay.accept(emojiData.isSelfSelected) emojiCountButton.setInitEmoji(emoji: EmojiData(emoji: Emojis.emoji(forIndex: index+1), count: emojiData.count)) emojiCountStackView.addArrangedSubview(emojiCountButton) } diff --git a/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/PostNavigationView.swift b/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/PostNavigationView.swift index b02c863e2..a89649e72 100644 --- a/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/PostNavigationView.swift +++ b/14th-team5-iOS/App/Sources/Presentation/PostDetail/Views/PostNavigationView.swift @@ -100,11 +100,11 @@ final class PostNavigationView: BaseView { } extension PostNavigationView { - func setData(data: PostListData) { + private func setData(data: PostListData) { if let author = data.author, let profileImageURL = author.profileImageURL, let url = URL(string: profileImageURL), !profileImageURL.isEmpty { - profileImageView.load(url: url) + profileImageView.kf.setImage(with: url) defaultNameLabel.isHidden = true } else { if let author = data.author, @@ -114,6 +114,8 @@ extension PostNavigationView { defaultNameLabel.text = "알" } + profileImageView.kf.base.image = nil + defaultNameLabel.isHidden = false profileImageView.backgroundColor = .gray800 } diff --git a/14th-team5-iOS/Data/Sources/Emoji/DTO/FetchEmojiDTO.swift b/14th-team5-iOS/Data/Sources/Emoji/DTO/FetchEmojiDTO.swift index 270edeadb..9a3e1e27c 100644 --- a/14th-team5-iOS/Data/Sources/Emoji/DTO/FetchEmojiDTO.swift +++ b/14th-team5-iOS/Data/Sources/Emoji/DTO/FetchEmojiDTO.swift @@ -32,8 +32,7 @@ struct FetchEmojiResponse: Codable { } private func containsCurrentUser(memberIds: [String]) -> Bool { -// let currentMemberId = FamilyUserDefaults.returnMyMemberId() - let currentMemberId = "01HJBNWZGNP1KJNMKWVZJ039HY" + let currentMemberId = FamilyUserDefaults.returnMyMemberId() return memberIds.contains(currentMemberId) } } diff --git a/14th-team5-iOS/Data/Sources/Post/PostList/DTO/PostListDTO.swift b/14th-team5-iOS/Data/Sources/Post/PostList/DTO/PostListDTO.swift index caec5e3d8..5146a3040 100644 --- a/14th-team5-iOS/Data/Sources/Post/PostList/DTO/PostListDTO.swift +++ b/14th-team5-iOS/Data/Sources/Post/PostList/DTO/PostListDTO.swift @@ -12,7 +12,7 @@ public struct PostListRequestDTO: Codable { let page: Int let size: Int let date: String - let memberId: String + let memberId: String? let sort: String } diff --git a/14th-team5-iOS/Data/Sources/Post/PostList/PostListAPI/PostListAPIWorker.swift b/14th-team5-iOS/Data/Sources/Post/PostList/PostListAPI/PostListAPIWorker.swift index 645096ba7..78e51c9e3 100644 --- a/14th-team5-iOS/Data/Sources/Post/PostList/PostListAPI/PostListAPIWorker.swift +++ b/14th-team5-iOS/Data/Sources/Post/PostList/PostListAPI/PostListAPIWorker.swift @@ -69,9 +69,9 @@ extension PostListAPIWorker: PostListRepositoryProtocol { } private func fetchTodayPostList(headers: [APIHeader]?, query: Domain.PostListQuery) -> RxSwift.Single { - let requestDTO = PostListRequestDTO(page: query.page, size: query.size, date: query.date, memberId: query.memberId, sort: query.sort) - let spec = PostListAPIs.fetchPostList(requestDTO).spec - return request(spec: spec, headers: headers) + let requestDTO = PostListRequestDTO(page: query.page, size: query.size, date: query.date, memberId: nil, sort: query.sort) + let spec = PostListAPIs.fetchPostList.spec + return request(spec: spec, headers: headers, parameters: requestDTO) .subscribe(on: Self.queue) .do { if let str = String(data: $0.1, encoding: .utf8) { @@ -81,9 +81,12 @@ extension PostListAPIWorker: PostListRepositoryProtocol { .map(PostListResponseDTO.self) .catchAndReturn(nil) .map { - let selfUploaded = $0?.results.map { $0.authorId == FamilyUserDefaults.getMyMemberId() }.isEmpty + let myMemberId = FamilyUserDefaults.getMyMemberId() + let familyCount = FamilyUserDefaults.getMemberCount() + + let selfUploaded = $0?.results.map { $0.authorId == myMemberId }.contains(true) ?? false let familyUploaded = $0?.results.count == FamilyUserDefaults.getMemberCount() - return $0?.toDomain(!(selfUploaded ?? true), familyUploaded) + return $0?.toDomain(selfUploaded, familyUploaded) } .asSingle() } diff --git a/14th-team5-iOS/Data/Sources/Post/PostList/PostListAPI/PostListAPIs.swift b/14th-team5-iOS/Data/Sources/Post/PostList/PostListAPI/PostListAPIs.swift index a10278a9f..01edad2e1 100644 --- a/14th-team5-iOS/Data/Sources/Post/PostList/PostListAPI/PostListAPIs.swift +++ b/14th-team5-iOS/Data/Sources/Post/PostList/PostListAPI/PostListAPIs.swift @@ -9,27 +9,16 @@ import Foundation import Core public enum PostListAPIs: API { - case fetchPostList(PostListRequestDTO) + case fetchPostList case fetchPostDetail(PostRequestDTO) var spec: APISpec { switch self { - case let .fetchPostList(query): - var urlString = "\(BibbiAPI.hostApi)/posts" - - var queryParams: [String] = [] - queryParams.append("page=\(query.page)") - queryParams.append("size=\(query.size)") - queryParams.append("date=\(query.date)") - queryParams.append("sort=\(query.sort)") - - if !queryParams.isEmpty { - urlString += "?" + queryParams.joined(separator: "&") - } - + case .fetchPostList: + let urlString = "\(BibbiAPI.hostApi)/posts" return APISpec(method: .get, url: urlString) case let .fetchPostDetail(query): - var urlString = "\(BibbiAPI.hostApi)/posts/\(query.postId)" + let urlString = "\(BibbiAPI.hostApi)/posts/\(query.postId)" return APISpec(method: .get, url: urlString) } }