Skip to content

Commit

Permalink
Merge branch 'develop' into TNT-205-alarmPage
Browse files Browse the repository at this point in the history
  • Loading branch information
FpRaArNkK authored Feb 3, 2025
2 parents 84c88a6 + 9dcef4f commit 8a41354
Show file tree
Hide file tree
Showing 29 changed files with 1,257 additions and 65 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,7 @@
"images" : [
{
"filename" : "Size=24, Type=smile.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
"idiom" : "universal"
}
],
"info" : {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// AutoSizingBottomSheetModifier.swift
// DesignSystem
//
// Created by 박민서 on 2/2/25.
// Copyright © 2025 yapp25thTeamTnT. All rights reserved.
//

import SwiftUI

/// 바텀시트의 높이를 자동 조정하는 ViewModifier
/// 내부 컨텐츠의 크기를 측정하여 적절한 높이를 설정합니다
struct AutoSizingBottomSheetModifier: ViewModifier {
/// 바텀시트 상단의 그래버 표시
let presentationDragIndicator: Visibility
/// 측정된 컨텐츠의 높이 (초기값 300)
@State private var contentHeight: CGFloat = 300

init(presentationDragIndicator: Visibility = .visible) {
self.presentationDragIndicator = presentationDragIndicator
}

func body(content: Content) -> some View {
content
.background(
GeometryReader { proxy in
Color.clear
.onAppear {
contentHeight = proxy.size.height + 50
}
.onChange(of: proxy.size.height) { _, newHeight in
contentHeight = newHeight + 50
}
}
)
.presentationDetents([.height(contentHeight)])
.presentationDragIndicator(presentationDragIndicator)
}
}

public extension View {
/// 뷰에 자동 크기 조정 바텀시트를 적용하는 Modifier
/// - Parameter presentationDragIndicator: 바텀시트 상단 Grabber의 가시성 설정 (기본값: .visible)
/// - Returns: 자동 크기 조정 바텀시트가 적용된 뷰
func autoSizingBottomSheet(presentationDragIndicator: Visibility = .visible) -> some View {
self.modifier(AutoSizingBottomSheetModifier(presentationDragIndicator: presentationDragIndicator))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
//
// TCalendarCell.swift
// DesignSystem
//
// Created by 박민서 on 2/1/25.
// Copyright © 2025 yapp25thTeamTnT. All rights reserved.
//

import FSCalendar

/// TCalendar에 사용되는 Cell 입니다
final class TCalendarCell: FSCalendarCell {
// MARK: Properties
static let identifier: String = "TCalendarCell"
static let cellSize: CGSize = CGSize(width: 51, height: 54)

/// Cell에 표시되는 날짜
private var customDate: Date?
/// Cell 이 선택되었는지 표시
private var isCellSelected: Bool = false
/// Cell 스타일
private var style: Style = .default
/// Cell에 표시되는 일정 카운트
private var eventCount: Int = 0
/// 주간/월간 모드인지 표시
private var isWeekMode: Bool = false

// MARK: UI Elements
private let dayLabel: UILabel = UILabel()
private let eventStackView: UIStackView = UIStackView()
private let eventIcon: UIImageView = UIImageView()
private let eventCountLabel: UILabel = UILabel()
private let backgroundContainer: UIView = UIView()

override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
setUpHierarchy()
setUpConstraint()
}

required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func setupUI() {
backgroundContainer.layer.cornerRadius = 8

dayLabel.font = Typography.FontStyle.body2Medium.uiFont
dayLabel.textAlignment = .center

eventStackView.axis = .horizontal
eventStackView.spacing = 2
eventStackView.alignment = .center

eventIcon.image = UIImage(resource: .icnStar).withRenderingMode(.alwaysTemplate)
eventIcon.tintColor = UIColor(.red300)
eventIcon.contentMode = .scaleAspectFit
eventIcon.frame = CGRect(x: 0, y: 0, width: 12, height: 12)

eventCountLabel.font = Typography.FontStyle.label2Medium.uiFont
eventCountLabel.textColor = UIColor(.neutral400)
}

private func setUpHierarchy() {
eventStackView.addArrangedSubview(eventIcon)
eventStackView.addArrangedSubview(eventCountLabel)

contentView.addSubview(backgroundContainer)
contentView.addSubview(dayLabel)
contentView.addSubview(eventStackView)
}

private func setUpConstraint() {
dayLabel.translatesAutoresizingMaskIntoConstraints = false
eventStackView.translatesAutoresizingMaskIntoConstraints = false
backgroundContainer.translatesAutoresizingMaskIntoConstraints = false

NSLayoutConstraint.activate([
dayLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
dayLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5),
dayLabel.widthAnchor.constraint(equalToConstant: 32),
dayLabel.heightAnchor.constraint(equalToConstant: 32),

backgroundContainer.centerXAnchor.constraint(equalTo: dayLabel.centerXAnchor),
backgroundContainer.centerYAnchor.constraint(equalTo: dayLabel.centerYAnchor),
backgroundContainer.widthAnchor.constraint(equalTo: dayLabel.widthAnchor),
backgroundContainer.heightAnchor.constraint(equalTo: dayLabel.heightAnchor),

eventStackView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
eventStackView.topAnchor.constraint(equalTo: dayLabel.bottomAnchor, constant: 4)
])
}

/// 셀 스타일 표시 업데이트
private func updateAppearance() {
dayLabel.textColor = style.textColor
backgroundContainer.backgroundColor = style.backgroundColor
}

/// 일정 카운트 표시 업데이트
private func updateEventDisplay() {
eventCountLabel.text = "\(eventCount)"
let eventExists: Bool = eventCount > 0
eventStackView.isHidden = !eventExists
let presentCount: Bool = !isWeekMode && eventExists
eventCountLabel.isHidden = !presentCount
}

override func prepareForReuse() {
super.prepareForReuse()
// 날짜 및 선택 상태 초기화
customDate = nil
isCellSelected = false
isWeekMode = false

// 일정 관련 초기화
eventCount = 0
eventStackView.isHidden = true
eventCountLabel.text = nil

// 스타일 초기화
style = .default
updateAppearance()
updateEventDisplay()
}
}

extension TCalendarCell {
/// 셀 설정
func configure(
with date: Date,
isCellSelected: Bool,
eventCount: Int = 0,
isWeekMode: Bool = false
) {
self.customDate = date
self.isCellSelected = isCellSelected
self.eventCount = eventCount
self.isWeekMode = isWeekMode

// 현재 날짜 및 선택 상태를 반영, Style 설정
if isCellSelected {
self.style = .selected
} else if Calendar.current.isDateInToday(date) {
self.style = .today
} else {
self.style = .default
}

dayLabel.text = "\(Calendar.current.component(.day, from: date))"
self.updateAppearance()
self.updateEventDisplay()
}
}

extension TCalendarCell {
enum Style {
case `default`
case today
case selected

var textColor: UIColor {
switch self {
case .default, .today:
return UIColor(.neutral600)
case .selected:
return UIColor(.common0)
}
}

var backgroundColor: UIColor {
switch self {
case .default:
return .clear
case .today:
return UIColor(.neutral200)
case .selected:
return UIColor(.neutral900)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// TCalendarHeader.swift
// DesignSystem
//
// Created by 박민서 on 2/2/25.
// Copyright © 2025 yapp25thTeamTnT. All rights reserved.
//

import SwiftUI

/// TCalendarView의 헤더입니다
/// 월 이동 로직을 추가합니다
public struct TCalendarHeader<RightView: View>: View {

@Binding private var currentPage: Date
private var formatter: (Date) -> String
private var rightView: (() -> RightView)?

public init(
currentPage: Binding<Date>,
formatter: @escaping (Date) -> String,
rightView: (() -> RightView)? = nil
) {
self._currentPage = currentPage
self.formatter = formatter
self.rightView = rightView
}

public var body: some View {
HStack(spacing: 0) {
Button(action: {
movePage(-1)
}, label: {
Image(.icnTriangleLeft32px)
.resizable()
.frame(width: 32, height: 32)
})

Text("\(formatter(currentPage))")
.typographyStyle(.heading3, with: .neutral900)

Button(action: {
movePage(1)
}, label: {
Image(.icnTriangleRight32px)
.resizable()
.frame(width: 32, height: 32)
})
}
.frame(maxWidth: .infinity)
.overlay(alignment: .trailing) {
rightView?()
}
.padding(.vertical, 8)
.padding(.horizontal, 20)
}

private func movePage(_ direction: Int) {
if let nextPage = Calendar.current.date(byAdding: .month, value: direction, to: currentPage) {
currentPage = nextPage
}
}
}
Loading

0 comments on commit 8a41354

Please sign in to comment.