Skip to content

Commit

Permalink
Merge pull request #37 from Noostak/feat/NST-13/ConfirmedSchedule
Browse files Browse the repository at this point in the history
[Feat/NST-13] 회의확정 확인뷰
  • Loading branch information
oyslucy authored Feb 26, 2025
2 parents f63f253 + 8240282 commit f66dbbd
Show file tree
Hide file tree
Showing 12 changed files with 671 additions and 0 deletions.
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
}

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"
}
}
}
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

0 comments on commit f66dbbd

Please sign in to comment.