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

[TNT-233] 트레이너 수업 추가 화면 API, 화면 흐름 연결 완료 #81

Merged
merged 5 commits into from
Feb 12, 2025
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "icn_clock_red.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.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public struct TTextEditor: View {
private let footer: Footer?
/// Placeholder 텍스트
private let placeholder: String
/// 텍스트 에디터 사이즈
private let size: Size
/// 텍스트 필드 상태
@Binding private var status: Status
/// 입력된 텍스트
Expand All @@ -35,74 +37,58 @@ public struct TTextEditor: View {
/// TTextEditor 생성자
/// - Parameters:
/// - placeholder: Placeholder 텍스트 (기본값: "내용을 입력해주세요").
/// - size: 텍스트 에디터 사이즈.
/// - text: 입력된 텍스트를 관리하는 바인딩.
/// - textEditorStatus: 텍스트 에디터 상태를 관리하는 바인딩.
/// - footer: Textfield 하단에 표시될 `TTextEditor.FooterView`를 정의하는 클로저.
public init(
placeholder: String = "내용을 입력해주세요",
size: Size = .large,
text: Binding<String>,
textEditorStatus: Binding<Status>,
footer: () -> Footer? = { nil }
) {
self.placeholder = placeholder
self.size = size
self._text = text
self._status = textEditorStatus
self.footer = footer()
}

public var body: some View {
GeometryReader { geometry in
VStack(alignment: .leading, spacing: 8) {
ZStack(alignment: .topLeading) {
TextEditor(text: $text)
.autocorrectionDisabled()
.scrollDisabled(true)
.focused($isFocused)
.font(Typography.FontStyle.body1Medium.font)
.lineSpacing(Typography.FontStyle.body1Medium.lineSpacing)
.kerning(Typography.FontStyle.body1Medium.letterSpacing)
.tint(Color.neutral800)
.frame(minHeight: textHeight, maxHeight: .infinity)
.padding(.vertical, TTextEditor.verticalPadding)
.padding(.horizontal, TTextEditor.horizontalPadding)
.background(Color.common0)
.scrollContentBackground(.hidden)
.cornerRadius(8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(status.borderColor(isFocused: isFocused), lineWidth: status.borderWidth(isFocused: isFocused))
)
.onChange(of: text) {
withAnimation {
textHeight = getNewHeight(geometry: geometry)
}
}
.onAppear {
textHeight = getNewHeight(geometry: geometry)
}

if text.isEmpty {
Text(placeholder)
.typographyStyle(.body1Medium, with: .neutral400)
.padding(.vertical, TTextEditor.verticalPadding + 8)
.padding(.horizontal, TTextEditor.horizontalPadding + 4)
}
}
if let footer {
footer
VStack(alignment: .leading, spacing: 8) {
ZStack(alignment: .topLeading) {
TextEditor(text: $text)
.autocorrectionDisabled()
.scrollDisabled(true)
.focused($isFocused)
.font(Typography.FontStyle.body1Medium.font)
.lineSpacing(Typography.FontStyle.body1Medium.lineSpacing)
.kerning(Typography.FontStyle.body1Medium.letterSpacing)
.tint(Color.neutral800)
.frame(minHeight: textHeight, maxHeight: .infinity)
.padding(.vertical, TTextEditor.verticalPadding)
.padding(.horizontal, TTextEditor.horizontalPadding)
.background(Color.common0)
.scrollContentBackground(.hidden)
.cornerRadius(8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(status.borderColor(isFocused: isFocused), lineWidth: status.borderWidth(isFocused: isFocused))
)
.frame(height: size.height)

if text.isEmpty {
Text(placeholder)
.typographyStyle(.body1Medium, with: .neutral400)
.padding(.vertical, TTextEditor.verticalPadding + 8)
.padding(.horizontal, TTextEditor.horizontalPadding + 4)
}
}
if let footer {
footer
}
}
.frame(height: TTextEditor.defaultHeight)
}

private func getNewHeight(geometry: GeometryProxy) -> CGFloat {
let newHeight: CGFloat = TextUtility.calculateTextHeight(
boxWidth: geometry.size.width - TTextEditor.horizontalPadding * 2,
text: text,
style: .body1Medium
) + TTextEditor.verticalPadding * 2
return max(newHeight, TTextEditor.defaultHeight)
}
}

Expand Down Expand Up @@ -198,4 +184,20 @@ public extension TTextEditor {
}
}
}

/// TextEditor의 크기
enum Size {
case small
case large

/// 높이
var height: CGFloat {
switch self {
case .small:
return 52
case .large:
return 130
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public extension ImageResource {
static let icnTriangleDown: ImageResource = DesignSystemAsset.icnTriangleDown.imageResource
static let icnTriangleRight: ImageResource = DesignSystemAsset.icnTriangleRight.imageResource
static let icnClock: ImageResource = DesignSystemAsset.icnClock.imageResource
static let icnClockRed: ImageResource = DesignSystemAsset.icnClockRed.imageResource
static let icnStar: ImageResource = DesignSystemAsset.icnStar.imageResource
static let icnStarSmile: ImageResource = DesignSystemAsset.icnStarSmile.imageResource
static let icnWriteBlackFilled: ImageResource = DesignSystemAsset.icnWriteBlackFilled.imageResource
Expand Down
10 changes: 10 additions & 0 deletions TnT/Projects/Domain/Sources/DTO/Trainer/TrainerRequestDTO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,14 @@ public struct PostLessonReqDTO: Encodable {
let end: String
/// 트레이니 id
let traineeId: Int

public init(
start: String,
end: String,
traineeId: Int
) {
self.start = start
self.end = end
self.traineeId = traineeId
}
}
9 changes: 9 additions & 0 deletions TnT/Projects/Domain/Sources/Mapper/TrainerMapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,12 @@ public extension GetConnectedTraineeInfoResponseDTO {
)
}
}

public extension ActiveTraineeInfoResDTO {
func toEntity() -> TraineeListItemEntity {
return .init(
id: self.id,
name: self.name
)
}
}
16 changes: 16 additions & 0 deletions TnT/Projects/Domain/Sources/UseCase/TrainerUseCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,20 @@ public struct DefaultTrainerUseCase: TrainerRepository {
public func getConnectedTraineeInfo(trainerId: Int, traineeId: Int) async throws -> GetConnectedTraineeInfoResponseDTO {
return try await trainerRepository.getConnectedTraineeInfo(trainerId: trainerId, traineeId: traineeId)
}

public func getMonthlyLessonList(year: Int, month: Int) async throws -> GetMonthlyLessonListResDTO {
return try await trainerRepository.getMonthlyLessonList(year: year, month: month)
}

public func getActiveTraineesList() async throws -> GetActiveTraineesListResDTO {
return try await trainerRepository.getActiveTraineesList()
}

public func postLesson(reqDTO: PostLessonReqDTO) async throws -> PostLessonResDTO {
return try await trainerRepository.postLesson(reqDTO: reqDTO)
}

public func putCompleteLesson(lessonId: Int) async throws -> PutCompleteLessonResDTO {
return try await trainerRepository.putCompleteLesson(lessonId: lessonId)
}
}
Loading