Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat/NST-13] 회의확정 확인뷰 #37

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Noostak_iOS/Noostak_iOS/Domain/Entity/Schedule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ struct ExtendedSchedule {
let startTime: String
///약속 종료시각(1순위, 확정)
let endTime: String
///나의 가능 여부
let myInfo: MemberStatus
///가능한 친구
let availableMembers: [User]
///불가능한 친구
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ final class MemberAvailabilityChip: UIView {
setUpLayout()
}

func update(name: String, status: MemberStatus) {
self.chipLabel.text = name
self.status = status
setUpUI()
setUpLayout()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
Expand Down
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)
}
}
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
}
Comment on lines +11 to +16
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오! Reactor를 분리해서 관리하시나요! 좋습니다 👍👍👍
혹시 이렇게 진행하게된 이유를 여쭤봐도 될까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cell의 reactor를 가질 경우 별도의 바인딩 구현 없이 vc에서 바로 reactor를 주입할 수 있습니다 !


let initialState: State

init(user: User, status: MemberStatus) {
self.initialState = State(user: user, status: status)
}
}
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
}
}
}
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
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions Noostak_iOS/Noostak_iOS/Global/Utils/NSTDateUtility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public extension NSTDateUtility {
case HHmm
case EEMMdd
case MMddEE
case MMddHHmm

var format: String {
switch self {
Expand All @@ -77,6 +78,8 @@ public extension NSTDateUtility {
return "EE\nMM/dd"
case .MMddEE:
return "M월 d일 (EE)"
case .MMddHHmm:
return "MM/dd HH:mm"
Comment on lines +81 to +82
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

잘 쓰는 구만

}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ let mockInProgressData: [ExtendedSchedule] = [
date: "2024-09-05T10:00:00",
startTime: "2024-09-05T10:00:00",
endTime: "2024-09-05T18:00:00",
myInfo: .available,
availableMembers: [],
unavailableMembers: [],
groupMemberCount: 24,
Expand All @@ -86,6 +87,7 @@ let mockInProgressData: [ExtendedSchedule] = [
date: "2024-09-05T10:00:00",
startTime: "2024-09-05T10:00:00",
endTime: "2024-09-05T18:00:00",
myInfo: .available,
availableMembers: [],
unavailableMembers: [],
groupMemberCount: 23,
Expand All @@ -99,6 +101,7 @@ let mockInProgressData: [ExtendedSchedule] = [
date: "2024-09-05T10:00:00",
startTime: "2024-09-05T10:00:00",
endTime: "2024-09-05T18:00:00",
myInfo: .available,
availableMembers: [],
unavailableMembers: [],
groupMemberCount: 24,
Expand All @@ -114,6 +117,7 @@ let mockConfirmedData: [ExtendedSchedule] = [
date: "2024-09-05T10:00:00",
startTime: "2024-09-05T10:00:00",
endTime: "2024-09-05T18:00:00",
myInfo: .available,
availableMembers: [],
unavailableMembers: [],
groupMemberCount: 24,
Expand All @@ -127,6 +131,7 @@ let mockConfirmedData: [ExtendedSchedule] = [
date: "2024-09-05T10:00:00",
startTime: "2024-09-05T10:00:00",
endTime: "2024-09-05T18:00:00",
myInfo: .available,
availableMembers: [],
unavailableMembers: [],
groupMemberCount: 23,
Expand Down
Loading