diff --git a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj index 1477d75..fd01d52 100644 --- a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj +++ b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj @@ -110,6 +110,9 @@ 34FF6C60292B8BC9002AFD4D /* QuestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */; }; 34FF6C64292B8C26002AFD4D /* RxCocoa-Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C63292B8C26002AFD4D /* RxCocoa-Dynamic */; }; 9B1CFB3F292B585700CCE97A /* QuestDTO+Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B1CFB3E292B585700CCE97A /* QuestDTO+Mapping.swift */; }; + 9BD8CCFB2937407100E6EA2F /* FollowingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8CCFA2937407100E6EA2F /* FollowingCell.swift */; }; + 9BD8CD00293829DD00E6EA2F /* FollowingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8CCFF293829DD00E6EA2F /* FollowingView.swift */; }; + 9BD8CD022938418500E6EA2F /* LastFollowingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8CD012938418500E6EA2F /* LastFollowingCell.swift */; }; A50DE906292B53D900E1FD60 /* DefaultQuestsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50DE905292B53D900E1FD60 /* DefaultQuestsRepository.swift */; }; A50DE90B292B73B900E1FD60 /* FirebaseDatabaseSwift in Frameworks */ = {isa = PBXBuildFile; productRef = A50DE90A292B73B900E1FD60 /* FirebaseDatabaseSwift */; }; A50DE911292B74C500E1FD60 /* DTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50DE910292B74C500E1FD60 /* DTO.swift */; }; @@ -250,6 +253,9 @@ 34EE6EB62924C674005AF583 /* QuestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestView.swift; sourceTree = ""; }; 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestViewModel.swift; sourceTree = ""; }; 9B1CFB3E292B585700CCE97A /* QuestDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "QuestDTO+Mapping.swift"; sourceTree = ""; }; + 9BD8CCFA2937407100E6EA2F /* FollowingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingCell.swift; sourceTree = ""; }; + 9BD8CCFF293829DD00E6EA2F /* FollowingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingView.swift; sourceTree = ""; }; + 9BD8CD012938418500E6EA2F /* LastFollowingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastFollowingCell.swift; sourceTree = ""; }; A50DE905292B53D900E1FD60 /* DefaultQuestsRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultQuestsRepository.swift; sourceTree = ""; }; A50DE910292B74C500E1FD60 /* DTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DTO.swift; sourceTree = ""; }; A50F9A3329266F45005C00FE /* NetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = ""; }; @@ -787,6 +793,9 @@ 34874A9F292509A4000570DF /* QuestViewHeader.swift */, 347D258A292C60F40038FCA2 /* StatusView.swift */, 347D258C292C6E220038FCA2 /* MessageBubble.swift */, + 9BD8CCFA2937407100E6EA2F /* FollowingCell.swift */, + 9BD8CCFF293829DD00E6EA2F /* FollowingView.swift */, + 9BD8CD012938418500E6EA2F /* LastFollowingCell.swift */, 345687F52937430200CA51E3 /* PlanDatePickerView.swift */, 345687F729374D2500CA51E3 /* DayNamePickerView.swift */, 345687F92937815900CA51E3 /* QuantityView.swift */, @@ -1155,6 +1164,7 @@ 34A529D529247932001BAD34 /* AppCoordinator.swift in Sources */, B50078D629222F3F0070AFC4 /* CircleCheckView.swift in Sources */, 3499552729235D1E007AB99E /* BrowseItemViewModel.swift in Sources */, + 9BD8CCFB2937407100E6EA2F /* FollowingCell.swift in Sources */, 347D258B292C60F40038FCA2 /* StatusView.swift in Sources */, 34642AB62925D9E40052FA0E /* UserInfoView.swift in Sources */, 349955292923600A007AB99E /* BrowseViewController.swift in Sources */, @@ -1162,6 +1172,7 @@ 34EE6EB72924C674005AF583 /* QuestView.swift in Sources */, B58DFC0A29227DA800C68A4B /* CalendarCell.swift in Sources */, 3499551529232533007AB99E /* UIColor+.swift in Sources */, + 9BD8CD00293829DD00E6EA2F /* FollowingView.swift in Sources */, 342830F8292E1B7400AE811B /* PlainField.swift in Sources */, 34A529DA29247B9C001BAD34 /* AppDIContainer.swift in Sources */, 340A724B29348C2200B26AA6 /* DefaultAuthUseCase.swift in Sources */, @@ -1190,6 +1201,7 @@ A5AC96E829223F27003B7637 /* RealmQuestsStorage.swift in Sources */, 345687F829374D2500CA51E3 /* DayNamePickerView.swift in Sources */, 349955122923220E007AB99E /* SwiftUIPreview.swift in Sources */, + 9BD8CD022938418500E6EA2F /* LastFollowingCell.swift in Sources */, 3449AD6029222B3900B87619 /* UserInfoCell.swift in Sources */, 34ACC32F291DE9C000741371 /* SceneDelegate.swift in Sources */, 34A529D829247A87001BAD34 /* HomeCoordinator.swift in Sources */, diff --git a/DailyQuest/DailyQuest/Presentation/Home/View/FollowingCell.swift b/DailyQuest/DailyQuest/Presentation/Home/View/FollowingCell.swift new file mode 100644 index 0000000..72871cb --- /dev/null +++ b/DailyQuest/DailyQuest/Presentation/Home/View/FollowingCell.swift @@ -0,0 +1,66 @@ +// +// FollowingCell.swift +// DailyQuest +// +// Created by 이다연 on 2022/11/30. +// + +import UIKit +import SnapKit + +final class FollowingCell: UICollectionViewCell { + + static let reuseIdentifier = "FollowingCell" + + private lazy var userImage: UIImageView = { + let userImage = UIImageView() + userImage.image = UIImage(systemName: "person.circle") + userImage.clipsToBounds = true + userImage.contentMode = .scaleAspectFill + userImage.layer.cornerRadius = 35.0 / 2 + return userImage + }() + + override init(frame:CGRect) { + super.init(frame: frame) + contentView.addSubview(userImage) + userImage.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + } + + public func configure(with name: String?) { + if name == nil { + userImage.image = UIImage(systemName: "person.circle") + } else{ + userImage.image = UIImage(named: name ?? "") + } + } + + override func prepareForReuse() { + super.prepareForReuse() + userImage.image = nil + } +} + + +#if canImport(SwiftUI) && DEBUG +import SwiftUI + +struct FollowingCellPreview: PreviewProvider{ + static var previews: some View { + UIViewPreview { + let cell = FollowingCell(frame: .zero) + return cell + }.previewLayout(.fixed(width: 40, height: 40)) + } +} +#endif diff --git a/DailyQuest/DailyQuest/Presentation/Home/View/FollowingView.swift b/DailyQuest/DailyQuest/Presentation/Home/View/FollowingView.swift new file mode 100644 index 0000000..d6865ea --- /dev/null +++ b/DailyQuest/DailyQuest/Presentation/Home/View/FollowingView.swift @@ -0,0 +1,113 @@ +// +// FollowingView.swift +// DailyQuest +// +// Created by 이다연 on 2022/12/01. +// + +import UIKit +import SnapKit + +class FollowingView: UIView { + + override func draw(_ rect: CGRect) { + super.draw(rect) + } + + private lazy var titleLabel: UILabel = { + let titleLabel = UILabel() + titleLabel.text = "Following" + titleLabel.textColor = .maxViolet + titleLabel.font = UIFont.boldSystemFont(ofSize: 32) + + return titleLabel + }() + + private lazy var followingView : UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .horizontal + layout.minimumInteritemSpacing = 1.0 + layout.itemSize = CGSize(width: 35, height: 35) + layout.sectionInset = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10) + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + collectionView.showsHorizontalScrollIndicator = false + collectionView.isPagingEnabled = true + collectionView.register(FollowingCell.self, forCellWithReuseIdentifier: FollowingCell.reuseIdentifier) + collectionView.register(LastFollowingCell.self, forCellWithReuseIdentifier: LastFollowingCell.reuseIdentifier ) + collectionView.dataSource = self + collectionView.delegate = self + return collectionView + }() + + override init(frame: CGRect = .zero) { + super.init(frame: frame) + addSubviews() + setupConstraints() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func addSubviews() { + addSubview(titleLabel) + addSubview(followingView) + } + + private func setupConstraints() { + titleLabel.snp.makeConstraints { make in + make.left.equalToSuperview().inset(10) + make.height.equalTo(75) + } + + followingView.snp.makeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(5) + make.width.equalToSuperview() + make.height.equalTo(35) + } + } +} + +extension FollowingView: UICollectionViewDelegate { + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + print("User tapped on item \(indexPath.row)") + } +} + +extension FollowingView: UICollectionViewDataSource { + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return 4 + } + + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + if indexPath.row == collectionView.numberOfItems(inSection: 0) - 1 { + guard let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: LastFollowingCell.reuseIdentifier, for: indexPath) as? LastFollowingCell else { + return UICollectionViewCell(frame: .zero) + } + return myCell + } else { + guard let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: FollowingCell.reuseIdentifier, for: indexPath) as? FollowingCell else { + return UICollectionViewCell(frame: .zero) + } + myCell.configure(with: nil) + return myCell + } + } +} + +#if canImport(SwiftUI) && DEBUG +import SwiftUI + +struct FollowingViewPreview: PreviewProvider{ + static var previews: some View { + UIViewPreview { + let view = FollowingView(frame: .zero) + return view + }.previewLayout(.sizeThatFits) + } +} +#endif + + diff --git a/DailyQuest/DailyQuest/Presentation/Home/View/LastFollowingCell.swift b/DailyQuest/DailyQuest/Presentation/Home/View/LastFollowingCell.swift new file mode 100644 index 0000000..d69c131 --- /dev/null +++ b/DailyQuest/DailyQuest/Presentation/Home/View/LastFollowingCell.swift @@ -0,0 +1,54 @@ +// +// LastFollowingCell.swift +// DailyQuest +// +// Created by 이다연 on 2022/12/01. +// + +import UIKit + +final class LastFollowingCell: UICollectionViewCell { + + static let reuseIdentifier = "LastFollowingCell" + + private lazy var plusButton: UIButton = { + var config = UIButton.Configuration.maxStyle() + let plusButton = UIButton(configuration: config) + + return plusButton + }() + + override init(frame:CGRect) { + super.init(frame: frame) + contentView.addSubview(plusButton) + plusButton.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + } + + override func prepareForReuse() { + super.prepareForReuse() + } +} + + +#if canImport(SwiftUI) && DEBUG +import SwiftUI + +struct LastFollowingCellPreview: PreviewProvider{ + static var previews: some View { + UIViewPreview { + let cell = LastFollowingCell(frame: .zero) + return cell + }.previewLayout(.fixed(width: 40, height: 40)) + } +} +#endif diff --git a/DailyQuest/DailyQuest/Presentation/Home/ViewController/HomeViewController.swift b/DailyQuest/DailyQuest/Presentation/Home/ViewController/HomeViewController.swift index 1b15ac6..2034e44 100644 --- a/DailyQuest/DailyQuest/Presentation/Home/ViewController/HomeViewController.swift +++ b/DailyQuest/DailyQuest/Presentation/Home/ViewController/HomeViewController.swift @@ -21,6 +21,13 @@ final class HomeViewController: UIViewController { private var disposableBag = DisposeBag() private var questViewDelegate: QuestViewDelegate? + private lazy var stackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + + return stackView + }() + private lazy var questView: QuestView = { let questView = QuestView() @@ -31,6 +38,10 @@ final class HomeViewController: UIViewController { return QuestViewHeader() }() + private lazy var followingView: FollowingView = { + return FollowingView() + }() + // MARK: - Life Cycle static func create(with viewModel: QuestViewModel) -> HomeViewController { let vc = HomeViewController() @@ -41,15 +52,28 @@ final class HomeViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + questViewDelegate = QuestViewDelegate(header: questViewHeader) + questView.delegate = questViewDelegate + view.backgroundColor = .white - view.addSubview(questView) + stackView.addArrangedSubview(followingView) + stackView.addArrangedSubview(questView) - questView.delegate = questViewDelegate - questView.snp.makeConstraints { make in - make.edges.equalToSuperview() + + view.addSubview(stackView) + + + stackView.snp.makeConstraints { make in + make.width.equalToSuperview() + make.height.equalToSuperview() + } + + followingView.snp.makeConstraints { make in + make.width.equalTo(view.snp.width) + make.height.equalTo(125) } bind() @@ -76,4 +100,9 @@ final class HomeViewController: UIViewController { private func setup(questViewModel: QuestViewModel) { questView.setup(with: questViewModel) } + + private func configureFollowingView() { + + } + }