-
Notifications
You must be signed in to change notification settings - Fork 0
Style/#76 시술 플로우 화면 구현 #83
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
Changes from all commits
2da02aa
e494741
23003bb
283d076
8de4a6b
b1ba630
1da567c
b6f5d19
d0b41e3
5739273
a00d593
d9d3f9c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,14 +8,15 @@ | |
| import SwiftUI | ||
|
|
||
| struct SelectedTreatmentView: View { | ||
| @ObservedObject var viewModel: NoTreatmentViewModel | ||
| let selectedTreatments: [TreatmentEntity] | ||
| let removeTreatment: (TreatmentEntity) -> Void | ||
|
|
||
| private let itemHeight: CGFloat = 34.adjustedH | ||
| private let spacing: CGFloat = 16.adjustedH | ||
| private let maxVisibleCount = 3 | ||
|
|
||
| private var scrollViewHeight: CGFloat { | ||
| let count = min(viewModel.selectedTreatments.count, maxVisibleCount) | ||
| let count = min(selectedTreatments.count, maxVisibleCount) | ||
| let contentHeight = CGFloat(count) * itemHeight + CGFloat(max(count - 1, 0)) * spacing | ||
| return contentHeight + 24.adjustedH | ||
| } | ||
|
|
@@ -47,20 +48,20 @@ struct SelectedTreatmentView: View { | |
| ) | ||
| ScrollView(.vertical, showsIndicators: false) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 스크롤되는것도 gif 한번만 첨부해주세요! |
||
| VStack(spacing: spacing) { | ||
| ForEach(viewModel.selectedTreatments, id: \.id) { treatment in | ||
| ForEach(selectedTreatments, id: \.id) { treatment in | ||
| TreatmentRowView( | ||
| displayMode: .summary, | ||
| treatmentEntity: treatment, | ||
| isSelected: .constant(true), | ||
| action: { viewModel.removeTreatment(treatment) } | ||
| action: { removeTreatment(treatment) } | ||
| ) | ||
| .frame(height: itemHeight) | ||
| } | ||
| } | ||
| .padding(.vertical, 14.adjustedH) | ||
| } | ||
| .frame(height: scrollViewHeight) | ||
| .scrollDisabled(viewModel.selectedTreatments.count <= maxVisibleCount) | ||
| .scrollDisabled(selectedTreatments.count <= maxVisibleCount) | ||
| .padding(.horizontal, 24.5.adjustedW) | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| // | ||
| // TreatmentSearchBarTextField.swift | ||
| // Cherrish-iOS | ||
| // | ||
| // Created by 어재선 on 1/16/26. | ||
| // | ||
|
|
||
| import SwiftUI | ||
|
|
||
| struct TreatmentSearchBarTextField: View { | ||
| @Binding var text: String | ||
| let enter: () -> Void | ||
| var isDisabled: Bool | ||
| var body: some View { | ||
|
|
||
| VStack { | ||
|
|
||
|
Comment on lines
+16
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이거 엔터좀여 |
||
| HStack{ | ||
| ZStack { | ||
| if text.isEmpty { | ||
| HStack{ | ||
| TypographyText("원하시는 시술을 적어주세요.", style: .body1_r_14, color: .gray600) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 원하시는 -> 원하는 |
||
| Spacer() | ||
| } | ||
| } | ||
| TextField("" ,text: $text) | ||
| .foregroundStyle(.gray1000) | ||
| .typography(.body1_m_14) | ||
| .multilineTextAlignment(.leading) | ||
| .tint(.gray1000) | ||
| .onSubmit { | ||
| enter() | ||
| } | ||
|
Comment on lines
+26
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial 비활성 상태에서도 엔터 제출이 실행됩니다
✅ 제안 수정- TextField("" ,text: $text)
+ TextField("" ,text: $text)
.foregroundStyle(.gray1000)
.typography(.body1_m_14)
.multilineTextAlignment(.leading)
.tint(.gray1000)
+ .disabled(isDisabled)
.onSubmit {
- enter()
+ guard !isDisabled else { return }
+ enter()
}Also applies to: 45-45 🤖 Prompt for AI Agents |
||
| } | ||
| .padding(.vertical, 8.adjustedH) | ||
| .padding(.leading, 16.5.adjustedW) | ||
| Button{ | ||
|
Comment on lines
+35
to
+37
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이부분 엔터해주세용 |
||
| enter() | ||
| } label: { | ||
| ZStack { | ||
| Image(.search) | ||
| } | ||
| } | ||
| .padding(.leading, 8) | ||
| .disabled(isDisabled) | ||
| } | ||
| .padding(.trailing, 16.5.adjustedW) | ||
| } | ||
| .background{ | ||
| RoundedRectangle(cornerRadius: 30) | ||
| .foregroundStyle(.gray200) | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // | ||
| // Treatment.swift | ||
| // Cherrish-iOS | ||
| // | ||
| // Created by 어재선 on 1/16/26. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| enum Treatment: Int, CaseIterable, Identifiable { | ||
| case targetDdaySetting = 1 | ||
| case treatmentFilter | ||
| case downTimeSetting | ||
|
|
||
| var id: Self { self } | ||
|
|
||
| var title: String { | ||
| switch self { | ||
| case .targetDdaySetting: | ||
| return "목표 디데이 설정" | ||
| case .treatmentFilter: | ||
| return "시술 필터링" | ||
| case .downTimeSetting: | ||
| return "다운타임 설정" | ||
| } | ||
| } | ||
|
|
||
| var isFirst: Bool { self == Self.allCases.first } | ||
| var isLast: Bool { self == Self.allCases.last } | ||
| } | ||
|
|
||
| // MARK: - Navigation | ||
| extension Treatment { | ||
| mutating func next() { | ||
| let allCases = Self.allCases | ||
|
|
||
| guard let currentIndex = allCases.firstIndex(of: self), | ||
| currentIndex + 1 < allCases.count else { return } | ||
|
|
||
| self = allCases[allCases.index(after: currentIndex)] | ||
|
|
||
| } | ||
|
|
||
| mutating func previous() { | ||
| let allCases = Self.allCases | ||
|
|
||
| guard let currentIndex = allCases.firstIndex(of: self), | ||
| currentIndex > 0 else { return } | ||
|
|
||
| self = allCases[allCases.index(before: currentIndex)] | ||
|
|
||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| // | ||
| // TreatmentFilterView.swift | ||
| // Cherrish-iOS | ||
| // | ||
| // Created by 어재선 on 1/16/26. | ||
| // | ||
|
|
||
| import SwiftUI | ||
|
|
||
| struct TreatmentFilterView: View { | ||
| @ObservedObject var viewModel: TreatmentViewModel | ||
| var body: some View { | ||
| VStack { | ||
| TreatmentSearchBarTextField(text: $viewModel.searchText, enter: { }, isDisabled: !viewModel.searchText.isEmpty) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 개행 + 엔터좀요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 검색 버튼이 사실상 무동작/비활성입니다
✅ 최소 수정 예시- TreatmentSearchBarTextField(text: $viewModel.searchText, enter: { }, isDisabled: !viewModel.searchText.isEmpty)
+ TreatmentSearchBarTextField(
+ text: $viewModel.searchText,
+ enter: { viewModel.filterTreatments(by: viewModel.searchText) },
+ isDisabled: viewModel.searchText.isEmpty
+ )🤖 Prompt for AI Agents |
||
|
|
||
| ScrollView(.vertical, showsIndicators: false) { | ||
| HStack(alignment: .top,spacing: 4) { | ||
| TypographyText("◎", style: .body3_r_12, color: .gray600) | ||
|
|
||
| VStack(alignment: .leading, spacing: 0) { | ||
| TypographyText("본 정보는 인터넷 빅테이터 검색 및 분석을 통해 수집된 정보이며,공식적인 의료 정보가 아닙니다. ", style: .body3_r_12, color: .gray600) | ||
| .lineLimit(2) | ||
|
|
||
| } | ||
|
|
||
| Spacer() | ||
|
|
||
| } | ||
| if viewModel.filteredTreatments.isEmpty { | ||
| ForEach(viewModel.treatments, id: \.id) { treatment in | ||
| TreatmentRowView( | ||
| displayMode: .checkBoxView, | ||
| treatmentEntity: treatment, | ||
| isSelected: .constant(viewModel.isSelected(treatment)), | ||
| action: { viewModel.addTreatment(treatment) } | ||
| ) | ||
| } | ||
| } else { | ||
| ForEach(viewModel.filteredTreatments, id: \.id) { | ||
| treatment in | ||
| TreatmentRowView( | ||
| displayMode: .checkBoxView, | ||
| treatmentEntity: treatment, | ||
| isSelected: .constant(viewModel.isSelected(treatment)), | ||
| action: { viewModel.addTreatment(treatment) } | ||
| ) | ||
| } | ||
| } | ||
|
Comment on lines
+29
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 검색 결과 0건이면 전체 리스트로 되돌아가는 버그 현재는 🐛 제안 수정- if viewModel.filteredTreatments.isEmpty {
- ForEach(viewModel.treatments, id: \.id) { treatment in
+ if viewModel.searchText.isEmpty {
+ ForEach(viewModel.treatments, id: \.id) { treatment in
TreatmentRowView(
displayMode: .checkBoxView,
treatmentEntity: treatment,
isSelected: .constant(viewModel.isSelected(treatment)),
action: { viewModel.addTreatment(treatment) }
)
}
} else {
ForEach(viewModel.filteredTreatments, id: \.id) {
treatment in
TreatmentRowView(
displayMode: .checkBoxView,
treatmentEntity: treatment,
isSelected: .constant(viewModel.isSelected(treatment)),
action: { viewModel.addTreatment(treatment) }
)
}
}🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| } | ||
| .padding(.horizontal, 24.5.adjustedW) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,132 @@ | ||||||
| // | ||||||
| // TreatmentView.swift | ||||||
| // Cherrish-iOS | ||||||
| // | ||||||
| // Created by 어재선 on 1/16/26. | ||||||
| // | ||||||
|
|
||||||
| import SwiftUI | ||||||
|
|
||||||
| struct TreatmentView: View { | ||||||
| @StateObject private var viewModel: TreatmentViewModel | ||||||
|
|
||||||
| init(viewModel: TreatmentViewModel = TreatmentViewModel()) { | ||||||
| _viewModel = StateObject(wrappedValue: viewModel) | ||||||
| } | ||||||
| var body: some View { | ||||||
| VStack { | ||||||
| CherrishNavigationBar( | ||||||
| title:viewModel.state.title, | ||||||
| leftButtonAction: { | ||||||
| viewModel.previous() | ||||||
| }, | ||||||
| rightButtonAction: { | ||||||
|
|
||||||
| } | ||||||
| ) | ||||||
|
|
||||||
| ProgressBar( | ||||||
| totalSteps: Treatment.allCases.count, | ||||||
| currentStep: .constant(viewModel.step) | ||||||
| ) | ||||||
| .padding( .horizontal, 33.5.adjustedW) | ||||||
|
|
||||||
| VStack(spacing: 0){ | ||||||
| Group { | ||||||
| switch viewModel.state { | ||||||
| case .targetDdaySetting: | ||||||
| TargetDdaySettingView(dDayState: $viewModel.dDay, year: $viewModel.year, month: $viewModel.month, day: $viewModel.day) | ||||||
| .padding( .leading, 34.adjustedW) | ||||||
| .padding( .trailing, 33.adjustedW) | ||||||
| .id(viewModel.state) | ||||||
| case .treatmentFilter: | ||||||
| TreatmentFilterView(viewModel: viewModel) | ||||||
| case .downTimeSetting: | ||||||
| DownTimeSettingView(treatments: viewModel.selectedTreatments) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| Spacer() | ||||||
|
|
||||||
| Group { | ||||||
| if viewModel.state == .treatmentFilter { | ||||||
| if !viewModel.selectedTreatments.isEmpty { | ||||||
| SelectedTreatmentView(selectedTreatments: viewModel.selectedTreatments, removeTreatment: viewModel.removeTreatment(_:)) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| CherrishButton(title: "다음", type: .next, state: .constant(viewModel.canProceed ? .active : .normal)) { | ||||||
| viewModel.next() | ||||||
|
|
||||||
| } | ||||||
| .padding(.horizontal, 25.adjustedW) | ||||||
|
|
||||||
| } | ||||||
|
|
||||||
| Spacer() | ||||||
| .frame(height: 38.adjustedH) | ||||||
|
|
||||||
| } | ||||||
| .id(viewModel.step) | ||||||
| } | ||||||
| .ignoresSafeArea(.keyboard) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| //MARK: - TreatmentSelectedCategoryView | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MARK 주석 포맷을 SwiftLint 규칙에 맞게 수정하세요 (Line 76).
🧹 제안 수정-//MARK: - TreatmentSelectedCategoryView
+// MARK: - TreatmentSelectedCategoryView📝 Committable suggestion
Suggested change
🧰 Tools🪛 SwiftLint (0.57.0)[Warning] 76-76: MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...' (mark) 🤖 Prompt for AI Agents |
||||||
|
|
||||||
| private struct TreatmentSelectedCategory: View { | ||||||
| @ObservedObject var viewModel: NoTreatmentViewModel | ||||||
| let columns = [ | ||||||
| GridItem(.flexible()), | ||||||
| GridItem(.flexible()) | ||||||
| ] | ||||||
| var body: some View { | ||||||
| VStack { | ||||||
| Spacer() | ||||||
| .frame(height: 70.adjustedH) | ||||||
| HStack(spacing: 0) { | ||||||
| VStack(alignment: .leading, spacing: 0) { | ||||||
| TypographyText( | ||||||
| "요즘 가장 신경 쓰이는 ", | ||||||
| style: .title1_sb_18, | ||||||
| color: .gray1000 | ||||||
| ) | ||||||
| TypographyText( | ||||||
| "피부 고민은 무엇인가요?", | ||||||
| style: .title1_sb_18, | ||||||
| color: .gray1000 | ||||||
| ) | ||||||
| TypographyText( | ||||||
| "선택한 고민을 기준으로 시술 정보를 정리해줘요.", | ||||||
| style: .body1_m_14, | ||||||
| color: .gray700 | ||||||
| ) | ||||||
| } | ||||||
| Spacer() | ||||||
| } | ||||||
| Spacer() | ||||||
| .frame(height: 40.adjustedH) | ||||||
| LazyVGrid(columns: columns, spacing: 12) { | ||||||
| ForEach(TreatmentCategory.allCases, id: \.id) { catagory in | ||||||
| SelectionChip( | ||||||
| title: catagory.title, | ||||||
| isSelected: Binding( | ||||||
| get: { | ||||||
| viewModel.treatmentCatagory == catagory | ||||||
| }, | ||||||
| set: { | ||||||
| isSelected in | ||||||
| guard isSelected else { | ||||||
| return | ||||||
| } | ||||||
| viewModel.treatmentCatagory = catagory | ||||||
| } | ||||||
| ) | ||||||
| ) | ||||||
|
|
||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // | ||
| // TreatmentViewModel+Filter.swift | ||
| // Cherrish-iOS | ||
| // | ||
| // Created by 어재선 on 1/16/26. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| extension TreatmentViewModel { | ||
|
|
||
| func addTreatment(_ treatment: TreatmentEntity) { | ||
| guard !isSelected(treatment) else { return } | ||
| selectedTreatments.append(treatment) | ||
| } | ||
|
|
||
| func removeTreatment(_ treatment: TreatmentEntity) { | ||
| selectedTreatments.removeAll { $0.id == treatment.id } | ||
| } | ||
| func isSelected(_ treatment: TreatmentEntity) -> Bool { | ||
| selectedTreatments.contains(where: { $0.id == treatment.id }) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
뒤에 sheet 붙이는 네이밍으로 바꾸는건 어떨까요