-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from Noostak/feat/NST-13/ConfirmedSchedule
[Feat/NST-13] 회의확정 확인뷰
- Loading branch information
Showing
12 changed files
with
671 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
Noostak_iOS/Noostak_iOS/Global/Components/ScheduleInfoView/Cell/MemberAvailabilityCVC.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// | ||
// MemberAvailabilityCVC.swift | ||
// Noostak_iOS | ||
// | ||
// Created by 오연서 on 2/11/25. | ||
// | ||
|
||
import UIKit | ||
import SnapKit | ||
import Then | ||
import ReactorKit | ||
|
||
final class MemberAvailabilityCVC: UICollectionViewCell, View { | ||
|
||
// MARK: Properties | ||
static let identifier = "MemberAvailabilityCVC" | ||
var disposeBag = DisposeBag() | ||
|
||
// MARK: Views | ||
var chip = MemberAvailabilityChip(name: "", status: .available) | ||
|
||
// MARK: Init | ||
override init(frame: CGRect) { | ||
super.init(frame: frame) | ||
setUpHierarchy() | ||
setUpLayout() | ||
} | ||
|
||
required init?(coder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
// MARK: setUpHierarchy | ||
private func setUpHierarchy() { | ||
self.addSubview(chip) | ||
} | ||
|
||
// MARK: setUpLayout | ||
private func setUpLayout() { | ||
chip.snp.makeConstraints { | ||
$0.edges.equalToSuperview() | ||
} | ||
} | ||
} | ||
|
||
extension MemberAvailabilityCVC { | ||
func bind(reactor: MemberAvailabilityCellReactor) { | ||
self.chip.update(name: reactor.currentState.user.name, status: reactor.currentState.status) | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
...oostak_iOS/Global/Components/ScheduleInfoView/Reactor/MemberAvailabilityCellReactor.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// | ||
// MemberAvailabilityCellReactor.swift | ||
// Noostak_iOS | ||
// | ||
// Created by 오연서 on 2/11/25. | ||
// | ||
|
||
import ReactorKit | ||
import RxSwift | ||
|
||
final class MemberAvailabilityCellReactor: Reactor { | ||
typealias Action = NoAction | ||
struct State { | ||
let user: User | ||
let status: MemberStatus | ||
} | ||
|
||
let initialState: State | ||
|
||
init(user: User, status: MemberStatus) { | ||
self.initialState = State(user: user, status: status) | ||
} | ||
} |
219 changes: 219 additions & 0 deletions
219
Noostak_iOS/Noostak_iOS/Global/Components/ScheduleInfoView/ScheduleInfoView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
// | ||
// ScheduleInfoView.swift | ||
// Noostak_iOS | ||
// | ||
// Created by 오연서 on 2/11/25. | ||
// | ||
|
||
import UIKit | ||
import Then | ||
import SnapKit | ||
import RxSwift | ||
import RxCocoa | ||
import RxDataSources | ||
import ReactorKit | ||
|
||
enum ScheduleState { | ||
case inProgress | ||
case confirmed | ||
} | ||
|
||
final class ScheduleInfoView: UIView { | ||
// MARK: Properties | ||
var disposeBag = DisposeBag() | ||
private var state: ScheduleState | ||
|
||
// MARK: Views | ||
let scheduleDurationLabel = UILabel() | ||
let likeButton = LikeButton() | ||
private let scheduleInfoView = UIView() | ||
private let scheduleTimeTitleLabel = UILabel() | ||
let scheduleTimeLabel = UILabel() | ||
private let scheduleCategoryLabel = UILabel() | ||
var scheduleCategoryChip = ScheduleCategoryButton(category: .hobby, buttonType: .ReadOnly) | ||
let availableLabel = UILabel() | ||
var availableCollectionView: UICollectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) | ||
let unavailableLabel = UILabel() | ||
var unavailableCollectionView: UICollectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) | ||
|
||
// MARK: Init | ||
init(state: ScheduleState) { | ||
self.state = state | ||
super.init(frame: .zero) | ||
setUpFoundation() | ||
setUpHierarchy() | ||
setUpUI() | ||
setUpLayout() | ||
updateUI(isInProgress: state == .inProgress) | ||
} | ||
|
||
required init?(coder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
// MARK: setUpHierarchy | ||
private func setUpHierarchy() { | ||
self.addSubview(scheduleInfoView) | ||
[scheduleDurationLabel, likeButton, scheduleTimeTitleLabel, scheduleTimeLabel, | ||
scheduleCategoryLabel, scheduleCategoryChip, | ||
availableLabel, availableCollectionView, | ||
unavailableLabel, unavailableCollectionView].forEach { | ||
scheduleInfoView.addSubview($0) | ||
} | ||
} | ||
|
||
private func setUpFoundation() { | ||
self.backgroundColor = .appWhite | ||
} | ||
|
||
// MARK: setUpUI | ||
private func setUpUI() { | ||
scheduleDurationLabel.do { | ||
$0.font = .PretendardStyle.t4_b.font | ||
$0.textColor = .appBlack | ||
} | ||
|
||
likeButton.do { | ||
$0.isHidden = true | ||
} | ||
|
||
scheduleInfoView.do { | ||
$0.layer.cornerRadius = 20 | ||
$0.layer.borderColor = UIColor.appGray100.cgColor | ||
$0.layer.borderWidth = 1 | ||
} | ||
|
||
scheduleTimeTitleLabel.do { | ||
$0.text = "약속 시간" | ||
$0.font = .PretendardStyle.c3_r.font | ||
$0.textColor = .appBlack | ||
} | ||
|
||
scheduleTimeLabel.do { | ||
$0.font = .PretendardStyle.b4_sb.font | ||
$0.textColor = .appBlack | ||
} | ||
|
||
scheduleCategoryLabel.do { | ||
$0.text = "약속 유형" | ||
$0.font = .PretendardStyle.c3_r.font | ||
$0.textColor = .appBlack | ||
} | ||
|
||
availableLabel.do { | ||
$0.font = .PretendardStyle.c3_r.font | ||
$0.textColor = .appBlack | ||
} | ||
|
||
unavailableLabel.do { | ||
$0.font = .PretendardStyle.c3_r.font | ||
$0.textColor = .appBlack | ||
} | ||
} | ||
|
||
// MARK: setUpLayout | ||
private func setUpLayout() { | ||
scheduleInfoView.snp.makeConstraints { | ||
$0.edges.equalToSuperview() | ||
$0.bottom.equalTo(unavailableCollectionView.snp.bottom).offset(16) | ||
} | ||
|
||
scheduleDurationLabel.snp.makeConstraints { | ||
$0.top.equalToSuperview().offset(20) | ||
$0.leading.equalToSuperview().offset(16) | ||
} | ||
|
||
likeButton.snp.makeConstraints { | ||
$0.top.equalToSuperview().offset(16) | ||
$0.trailing.equalToSuperview().inset(16) | ||
$0.height.equalTo(30) | ||
$0.width.equalTo(50) | ||
} | ||
|
||
scheduleTimeTitleLabel.snp.makeConstraints { | ||
$0.top.leading.equalToSuperview().offset(16) | ||
} | ||
|
||
scheduleTimeLabel.snp.makeConstraints { | ||
$0.centerY.equalTo(scheduleTimeTitleLabel) | ||
$0.trailing.equalToSuperview().inset(16) | ||
} | ||
|
||
scheduleCategoryLabel.snp.makeConstraints { | ||
$0.top.equalTo(scheduleTimeTitleLabel.snp.bottom).offset(26) | ||
$0.leading.equalTo(scheduleTimeTitleLabel) | ||
} | ||
|
||
scheduleCategoryChip.snp.makeConstraints { | ||
$0.centerY.equalTo(scheduleCategoryLabel) | ||
$0.trailing.equalTo(scheduleTimeLabel) | ||
$0.height.equalTo(30) | ||
$0.width.equalTo(53) | ||
} | ||
|
||
self.state == .inProgress ? | ||
availableLabel.snp.makeConstraints { | ||
$0.top.equalTo(scheduleDurationLabel.snp.bottom).offset(16) | ||
$0.leading.equalTo(scheduleDurationLabel) | ||
} : availableLabel.snp.makeConstraints { | ||
$0.top.equalTo(scheduleCategoryLabel.snp.bottom).offset(26) | ||
$0.leading.equalTo(scheduleTimeTitleLabel) | ||
} | ||
|
||
availableCollectionView.snp.makeConstraints { | ||
$0.top.equalTo(availableLabel.snp.bottom).offset(10) | ||
$0.horizontalEdges.equalToSuperview().inset(16) | ||
} | ||
|
||
unavailableLabel.snp.makeConstraints { | ||
$0.top.equalTo(availableCollectionView.snp.bottom).offset(20) | ||
$0.leading.equalTo(scheduleTimeTitleLabel) | ||
} | ||
|
||
unavailableCollectionView.snp.makeConstraints { | ||
$0.top.equalTo(unavailableLabel.snp.bottom).offset(10) | ||
$0.horizontalEdges.equalToSuperview().inset(16) | ||
} | ||
} | ||
|
||
private func updateUI(isInProgress: Bool) { | ||
[scheduleDurationLabel, likeButton].forEach { $0.isHidden = !isInProgress } | ||
[scheduleTimeTitleLabel, scheduleTimeLabel, scheduleCategoryLabel, scheduleCategoryChip].forEach { $0.isHidden = isInProgress } | ||
} | ||
} | ||
|
||
// MARK: - 셀 좌측 정렬 | ||
final class LeftAlignedFlowLayout: UICollectionViewFlowLayout { | ||
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { | ||
guard let attributes = super.layoutAttributesForElements(in: rect) else { return nil } | ||
|
||
var rowAttributes: [UICollectionViewLayoutAttributes] = [] | ||
var previousY: CGFloat = -1 | ||
var rowStartX: CGFloat = 0 | ||
|
||
for attribute in attributes { | ||
let frame = attribute.frame | ||
let currentY = frame.origin.y | ||
|
||
if currentY != previousY { | ||
alignRow(rowAttributes, rowStartX: rowStartX) | ||
rowAttributes.removeAll() | ||
rowStartX = sectionInset.left | ||
} | ||
rowAttributes.append(attribute) | ||
previousY = currentY | ||
} | ||
alignRow(rowAttributes, rowStartX: rowStartX) // 마지막 줄 정렬 | ||
return attributes | ||
} | ||
|
||
func alignRow(_ rowAttributes: [UICollectionViewLayoutAttributes], rowStartX: CGFloat) { | ||
guard !rowAttributes.isEmpty else { return } | ||
|
||
var currentX = rowStartX | ||
for attribute in rowAttributes { | ||
attribute.frame.origin.x = currentX | ||
currentX += attribute.frame.width + minimumInteritemSpacing | ||
} | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
...OS/Noostak_iOS/Global/Resources/Assets.xcassets/icn_profile_camera.imageset/Contents.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"images" : [ | ||
{ | ||
"filename" : "ic_profile_camera.svg", | ||
"idiom" : "universal" | ||
} | ||
], | ||
"info" : { | ||
"author" : "xcode", | ||
"version" : 1 | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
...bal/Resources/Assets.xcassets/icn_profile_camera.imageset/ic_profile_camera.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.