From 9767a2a42da90f5cd812b53a2ac5e44c2bf62df0 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Sun, 1 Dec 2024 11:29:18 +0900 Subject: [PATCH 01/37] =?UTF-8?q?[Chore]=20#233=20-=20=EA=B8=B0=EA=B8=B0?= =?UTF-8?q?=EB=8C=80=EC=9D=91=20=EC=BD=94=EB=93=9C=20=EA=B0=84=EC=86=8C?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj | 4 ++++ .../Smeem-iOS/Global/Extensions/Double+.swift | 20 +++++++++++++++++ .../SwiftUI/CoachingContentView.swift | 8 +++---- .../SwiftUI/CustomSegmentedControl.swift | 22 +++++++------------ .../SwiftUI/ScrollableDiaryView.swift | 12 +++++----- .../SwiftUI/SwiftUINavigationView.swift | 19 ++++++++-------- .../DetailDiary/DetailDiaryCoachedView.swift | 4 ++-- 7 files changed, 54 insertions(+), 35 deletions(-) create mode 100644 Smeem-iOS/Smeem-iOS/Global/Extensions/Double+.swift diff --git a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj index 98cb013b..82d2a2a2 100644 --- a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj +++ b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 370BD0B32CFB65BE009560DB /* RandomTopicView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370BD0AA2CFB65BE009560DB /* RandomTopicView.swift */; }; 370BD0B42CFB65BE009560DB /* AlarmCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370BD0A32CFB65BE009560DB /* AlarmCollectionViewCell.swift */; }; 370BD0B52CFB65BE009560DB /* AlarmDefaultModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370BD0A42CFB65BE009560DB /* AlarmDefaultModel.swift */; }; + 370BD0B82CFBF50C009560DB /* Double+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370BD0B72CFBF50C009560DB /* Double+.swift */; }; 371107DA2AC99099007A4AC2 /* KeyboardFollowingLayoutHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371107D92AC99099007A4AC2 /* KeyboardFollowingLayoutHandler.swift */; }; 371107DD2ACAB571007A4AC2 /* BaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371107DC2ACAB571007A4AC2 /* BaseView.swift */; }; 371107DF2ACAB709007A4AC2 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371107DE2ACAB709007A4AC2 /* BaseViewController.swift */; }; @@ -244,6 +245,7 @@ 370BD0A92CFB65BE009560DB /* DiaryScrollerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryScrollerView.swift; sourceTree = ""; }; 370BD0AA2CFB65BE009560DB /* RandomTopicView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RandomTopicView.swift; sourceTree = ""; }; 370BD0AB2CFB65BE009560DB /* SeparationLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparationLine.swift; sourceTree = ""; }; + 370BD0B72CFBF50C009560DB /* Double+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+.swift"; sourceTree = ""; }; 371107D92AC99099007A4AC2 /* KeyboardFollowingLayoutHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardFollowingLayoutHandler.swift; sourceTree = ""; }; 371107DC2ACAB571007A4AC2 /* BaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseView.swift; sourceTree = ""; }; 371107DE2ACAB709007A4AC2 /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; @@ -664,6 +666,7 @@ 4A4FEB002B721956001BBDF3 /* Combine+.swift */, 4AB7C9182B75F9B500845733 /* GesturePublisher+.swift */, 4AF050EA2CEA300F0055BC3F /* MoyaProvier+.swift */, + 370BD0B72CFBF50C009560DB /* Double+.swift */, ); path = Extensions; sourceTree = ""; @@ -1925,6 +1928,7 @@ 4A004D5B2B4EE29A003C8936 /* PushTestService.swift in Sources */, 379789052AAC706800C61EF4 /* SmeemNavigationFactory.swift in Sources */, 37DCA65D2A475B5100FF8F90 /* RandomTopicResponse.swift in Sources */, + 370BD0B82CFBF50C009560DB /* Double+.swift in Sources */, 4ABCBCCC2BDE8E44003138A8 /* MySummaryService.swift in Sources */, 371107DA2AC99099007A4AC2 /* KeyboardFollowingLayoutHandler.swift in Sources */, 37B123B62CEEE58E00ED973A /* DetailDiaryCoachedView.swift in Sources */, diff --git a/Smeem-iOS/Smeem-iOS/Global/Extensions/Double+.swift b/Smeem-iOS/Smeem-iOS/Global/Extensions/Double+.swift new file mode 100644 index 00000000..e7e3e66d --- /dev/null +++ b/Smeem-iOS/Smeem-iOS/Global/Extensions/Double+.swift @@ -0,0 +1,20 @@ +// +// Double+.swift +// Smeem-iOS +// +// Created by Joon Baek on 12/1/24. +// + +import UIKit + +extension Double { + // 너비 기반 스케일링 (iPhone 13 mini) + func scaledByWidth() -> Double { + return (self / 375) * UIScreen.main.bounds.width + } + + // 높이 기반 스케일링 (iPhone 13 mini) + func scaledByHeight() -> Double { + return (self / 812) * UIScreen.main.bounds.height + } +} diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift index ca8d4667..81477e37 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift @@ -12,15 +12,15 @@ struct CoachingContentView: View { @Binding var coachingResponse: CoachingsResponse var body: some View { - VStack(spacing: screenHeight * (20 / screenHeight)) { + VStack(spacing: 20.scaledByHeight()) { Rectangle() - .frame(height: screenHeight * (8 / screenHeight)) + .frame(height: 8.scaledByHeight()) .foregroundStyle(Color(UIColor.gray100)) TabView(selection: $currentIndex) { ForEach(coachingResponse.corrections.indices, id: \.self) { item in ScrollView { - VStack(spacing: screenWidth * (8 / screenWidth)) { + VStack(spacing: 8.scaledByHeight()) { CoachingComparisonView(coachingResponse: $coachingResponse.corrections[item]) CoachingExplanationView(coachingResponse: $coachingResponse.corrections[item]) @@ -30,7 +30,7 @@ struct CoachingContentView: View { } .frame(width: screenWidth, height: screenHeight * (286 / screenHeight), alignment: .top) .tabViewStyle(.page(indexDisplayMode: .never)) - .padding(.horizontal, screenWidth * (16 / screenWidth)) + .padding(.horizontal, 16.scaledByWidth()) PageControl(currentPage: $currentIndex, coachingResponse: $coachingResponse) diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift index 9576441a..9bee5159 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift @@ -34,8 +34,8 @@ struct SegmentButton: View { var body: some View { Button(action: action) { Text(title) - .padding(.vertical, 8) - .padding(.horizontal, 11) + .padding(.vertical, 8.scaledByHeight()) + .padding(.horizontal, 11.scaledByWidth()) .frame(maxWidth: .infinity) .background(backgroundColor) .foregroundColor(foregroundColor) @@ -56,19 +56,13 @@ struct SegmentButton: View { } } -struct PreviewWrapper: View { - @State private var selectedIndex = 0 - let options = ["코칭 OFF", "코칭 ON"] - - var body: some View { - CustomSegmentedControl(selectedIndex: $selectedIndex, options: options) - .frame(height: 40) - .padding(117) - } -} - @available(iOS 17.0, *) #Preview { - PreviewWrapper() + @State var selectedIndex = 0 + let options = ["코칭 OFF", "코칭 ON"] + + CustomSegmentedControl(selectedIndex: $selectedIndex, options: options) + .frame(height: 32.scaledByHeight()) + .padding(117.scaledByWidth()) } diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/ScrollableDiaryView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/ScrollableDiaryView.swift index e334c2d3..ee90bbda 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/ScrollableDiaryView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/ScrollableDiaryView.swift @@ -29,8 +29,8 @@ struct ScrollableDiaryView: View { corrections: corrections, highlightIndex: selectedIndex != 0 ? currentIndex : -1 )) - .padding(.horizontal, screenHeight * (18 / screenHeight)) - .padding(.bottom, screenHeight * (16 / screenHeight)) + .padding(.horizontal, 18.scaledByHeight()) + .padding(.bottom, 16.scaledByHeight()) .foregroundColor(Color(UIColor.gray400)) .background( // 콘텐츠 크기를 측정하기 위한 백그라운드 GeometryReader { geometry in @@ -44,18 +44,18 @@ struct ScrollableDiaryView: View { // Footer (작성 날짜, 작성자) HStack { Spacer() - VStack(alignment: .trailing, spacing: screenWidth * (4 / screenWidth)) { + VStack(alignment: .trailing, spacing: 4.scaledByWidth()) { Text(dateText) Text(authorText) } .font(Font(UIFont.c3)) .foregroundColor(Color(UIColor.gray400)) } - .padding(.horizontal, screenWidth * (18 / screenWidth)) + .padding(.horizontal, 18.scaledByWidth()) } - .padding(.bottom, screenHeight * (16 / screenHeight)) + .padding(.bottom, 16.scaledByHeight()) } - .frame(maxHeight: contentHeight + screenHeight * (100 / screenHeight)) // 텍스트 높이에 따른 동적 변경 + .frame(maxHeight: contentHeight + 100.scaledByHeight()) // 텍스트 높이에 따른 동적 변경 } } } diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift index 95d30984..0f50c88d 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift @@ -14,11 +14,11 @@ enum NavigationbarType { struct SwiftUINavigationView: View { let navigationbarType: NavigationbarType + let options = ["코칭 OFF", "코칭 ON"] + @State private var showFloatingView = false @Binding var selectedIndex: Int - let options = ["코칭 OFF", "코칭 ON"] - var body: some View { HStack { // 뒤로가기 버튼 @@ -29,16 +29,17 @@ struct SwiftUINavigationView: View { Image("icnBack") .imageScale(.large) }) - .padding(.leading, 10 / screenWidth) + .padding(.leading, 12.scaledByWidth()) } else { - Spacer().frame(width: 30 / screenWidth) + Spacer().frame(width: 30.scaledByWidth()) } // 중앙 콘텐츠 (CustomSegmentedControl) if navigationbarType == .diaryDetails { CustomSegmentedControl(selectedIndex: $selectedIndex, options: options) - .frame(height: 32 / screenHeight) - .padding(65) + .frame(height: 32.scaledByHeight()) + .padding(.leading, 65.scaledByWidth()) + .padding(.trailing, 59.scaledByWidth()) } Spacer() @@ -50,7 +51,7 @@ struct SwiftUINavigationView: View { }, label: { Image("icnMore") }) - .padding(.trailing, 18 / screenWidth) + .padding(.trailing, 18.scaledByWidth()) .fullScreenCover(isPresented: $showFloatingView) { FloatingButtonsSwiftUIView() } @@ -61,10 +62,10 @@ struct SwiftUINavigationView: View { Text("닫기") .tint(.black) }) - .padding(.trailing, 18 / screenWidth) + .padding(.trailing, 18.scaledByWidth()) } } - .frame(height: screenHeight * (66 / screenHeight)) + .frame(height: 54.scaledByHeight()) } } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index 7dca18fb..888742d0 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -15,7 +15,7 @@ struct DetailDiaryCoachedView: View { @State private var selectedIndex = 0 var body: some View { - VStack(spacing: screenWidth * (16 / screenWidth)) { + VStack(spacing: 16.scaledByWidth()) { SwiftUINavigationView(navigationbarType: .diaryDetails, selectedIndex: $selectedIndex) @@ -34,7 +34,7 @@ struct DetailDiaryCoachedView: View { CoachingContentView(currentIndex: $currentIndex, coachingResponse: $coachingResponse) } else { - Spacer(minLength: screenHeight * (342 / screenHeight)) + Spacer(minLength: 342.scaledByHeight()) } } } From f1205e0d434895b385937f2962df5cb8f6df4e1d Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Tue, 3 Dec 2024 22:15:11 +0900 Subject: [PATCH 02/37] =?UTF-8?q?[Feat]=20#233=20-=20=EB=92=A4=EB=A1=9C?= =?UTF-8?q?=EA=B0=80=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UIComponents/SwiftUI/SwiftUINavigationView.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift index 0f50c88d..9916adae 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift @@ -10,6 +10,7 @@ import SwiftUI enum NavigationbarType { case coachingCompleted case diaryDetails + case hasEdited } struct SwiftUINavigationView: View { @@ -19,12 +20,14 @@ struct SwiftUINavigationView: View { @State private var showFloatingView = false @Binding var selectedIndex: Int + @Environment(\.dismiss) private var dismiss + var body: some View { HStack { // 뒤로가기 버튼 if navigationbarType == .diaryDetails { Button(action: { - // 뒤로가기 액션 + dismiss() // 화면 pop }, label: { Image("icnBack") .imageScale(.large) @@ -72,5 +75,7 @@ struct SwiftUINavigationView: View { #Preview { @State var defaultIndex = 0 - SwiftUINavigationView(navigationbarType: .diaryDetails, selectedIndex: $defaultIndex) + NavigationView { + SwiftUINavigationView(navigationbarType: .diaryDetails, selectedIndex: $defaultIndex) + } } From fb17b5a35e3353a5f55b84595cb2640f35e187dc Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Wed, 4 Dec 2024 00:06:25 +0900 Subject: [PATCH 03/37] [Feat] #233 - DetailDiaryCoachedView API --- .../Smeem-iOS/Global/Protocols/Store.swift | 1 + .../SwiftUI/CoachingContentView.swift | 21 ++--- .../SwiftUI/FloatingButtonsSwiftUIView.swift | 2 +- .../SwiftUI/SwiftUINavigationView.swift | 10 +-- .../DetailDiary/DetailDiaryResponse.swift | 32 ++++++-- .../Coaching/CoachingCompleteView.swift | 6 +- .../DetailDiary/DetailDiaryCoachedView.swift | 77 ++++++++++++++----- .../Controllers/EditDiaryViewController.swift | 5 ++ .../Home/HomeViewController.swift | 21 ++++- 9 files changed, 128 insertions(+), 47 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/Protocols/Store.swift b/Smeem-iOS/Smeem-iOS/Global/Protocols/Store.swift index b1d8052d..5ef8c0ed 100644 --- a/Smeem-iOS/Smeem-iOS/Global/Protocols/Store.swift +++ b/Smeem-iOS/Smeem-iOS/Global/Protocols/Store.swift @@ -12,5 +12,6 @@ protocol Store { associatedtype State var state: State { get } + @MainActor func send(action: Action) } diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift index 81477e37..bcf893c7 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift @@ -9,8 +9,9 @@ import SwiftUI struct CoachingContentView: View { @Binding var currentIndex: Int - @Binding var coachingResponse: CoachingsResponse - + @Binding var coachingsResponse: CoachingsResponse + @Binding var coachingResponse: [CoachingResponse] + var body: some View { VStack(spacing: 20.scaledByHeight()) { Rectangle() @@ -18,12 +19,11 @@ struct CoachingContentView: View { .foregroundStyle(Color(UIColor.gray100)) TabView(selection: $currentIndex) { - ForEach(coachingResponse.corrections.indices, id: \.self) { item in + ForEach(coachingResponse.indices, id: \.self) { item in ScrollView { VStack(spacing: 8.scaledByHeight()) { - CoachingComparisonView(coachingResponse: $coachingResponse.corrections[item]) - - CoachingExplanationView(coachingResponse: $coachingResponse.corrections[item]) + CoachingComparisonView(coachingResponse: $coachingResponse[item]) + CoachingExplanationView(coachingResponse: $coachingResponse[item]) } } } @@ -32,14 +32,15 @@ struct CoachingContentView: View { .tabViewStyle(.page(indexDisplayMode: .never)) .padding(.horizontal, 16.scaledByWidth()) - PageControl(currentPage: $currentIndex, - coachingResponse: $coachingResponse) + PageControl(currentPage: $currentIndex, coachingsResponse: $coachingsResponse) } } } + #Preview { @State var defaultIndex: Int = 0 - @State var coachingResponse = CoachingsResponse.empty - CoachingContentView(currentIndex: $defaultIndex, coachingResponse: $coachingResponse) + @State var coachingsResponse = CoachingsResponse.empty + @State var coachingResponse = CoachingsResponse.empty.corrections + CoachingContentView(currentIndex: $defaultIndex, coachingsResponse: $coachingsResponse, coachingResponse: $coachingResponse) } diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift index c2290fa4..60801039 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift @@ -45,7 +45,7 @@ struct FloatingButtonsSwiftUIView: View { .background(Color.gray.opacity(0.5)) Button(action: { - print("삭제하기 버튼 액션") + }) { Text("삭제하기") .font(.headline) diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift index 9916adae..bc4f0740 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift @@ -10,7 +10,7 @@ import SwiftUI enum NavigationbarType { case coachingCompleted case diaryDetails - case hasEdited + case unCoached } struct SwiftUINavigationView: View { @@ -25,9 +25,9 @@ struct SwiftUINavigationView: View { var body: some View { HStack { // 뒤로가기 버튼 - if navigationbarType == .diaryDetails { + if navigationbarType == .diaryDetails || navigationbarType == .unCoached { Button(action: { - dismiss() // 화면 pop + dismiss() }, label: { Image("icnBack") .imageScale(.large) @@ -48,7 +48,7 @@ struct SwiftUINavigationView: View { Spacer() // 오른쪽 버튼 - if navigationbarType == .diaryDetails { + if navigationbarType == .diaryDetails || navigationbarType == .unCoached { Button(action: { showFloatingView = true }, label: { @@ -76,6 +76,6 @@ struct SwiftUINavigationView: View { @State var defaultIndex = 0 NavigationView { - SwiftUINavigationView(navigationbarType: .diaryDetails, selectedIndex: $defaultIndex) + SwiftUINavigationView(navigationbarType: .unCoached, selectedIndex: $defaultIndex) } } diff --git a/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift b/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift index 0d2f934b..5d346e62 100644 --- a/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift +++ b/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift @@ -11,18 +11,36 @@ struct DetailDiaryResponse: Codable, Equatable { var content: String let createdAt: String let username: String - + let isUpdated: Bool // JSON 키에 맞게 수정 + var corrections: [CoachingResponse] // JSON 구조에 맞게 수정 + let correctionCount: Int + let correctionMaxCount: Int + static func == (lhs: DetailDiaryResponse, rhs: DetailDiaryResponse) -> Bool { return lhs.diaryId == rhs.diaryId } } -struct CorrentionsData: Codable { - let correntionId: Int - let before: String - let after: String -} +//struct CorrentionsData: Codable { +// let correntionId: Int +// let before: String +// let after: String +//} extension DetailDiaryResponse { - static let empty = DetailDiaryResponse(diaryId: 0, topic: "", content: "테스트임?", createdAt: "그래", username: "그래") + static let empty = DetailDiaryResponse(diaryId: 0, topic: "", content: "테스트임?", createdAt: "그래", username: "그래", isUpdated: true, corrections: [], correctionCount: 0, correctionMaxCount: 0) } + +//struct CoachingResponse: Codable, Equatable { +// let originalSentence: String +// let correctedSentence: String +// let reason: String +// let isCorrected: Bool +// +// enum CodingKeys: String, CodingKey { +// case originalSentence = "originalSentence" +// case correctedSentence = "correctedSentence" +// case reason +// case isCorrected = "isCorrected" +// } +//} diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/CoachingCompleteView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/CoachingCompleteView.swift index 68339247..2904a4ae 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/CoachingCompleteView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/CoachingCompleteView.swift @@ -56,7 +56,7 @@ struct CoachingCompleteView: View { .tabViewStyle(.page(indexDisplayMode: .never)) PageControl(currentPage: $currentIndex, - coachingResponse: $coachingResponse) + coachingsResponse: $coachingResponse) } } } @@ -64,11 +64,11 @@ struct CoachingCompleteView: View { struct PageControl: View { @Binding var currentPage: Int - @Binding var coachingResponse: CoachingsResponse + @Binding var coachingsResponse: CoachingsResponse var body: some View { HStack(spacing: 8) { - ForEach(coachingResponse.corrections.indices, id: \.self) { pagingIndex in + ForEach(coachingsResponse.corrections.indices, id: \.self) { pagingIndex in let isCurrentPage = currentPage == pagingIndex Capsule() diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index 888742d0..b014fb39 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -5,46 +5,87 @@ // Created by Joon Baek on 11/21/24. // +import Combine import SwiftUI struct DetailDiaryCoachedView: View { + @State private var coachingsResponse = CoachingsResponse(corrections: []) + @State private var response: DetailDiaryResponse? + @State private var isLoading = false + @State private var error: SmeemError? - @Binding var diaryText: String - @Binding var coachingResponse: CoachingsResponse + @Binding var diaryID: Int? @State var currentIndex = 0 @State private var selectedIndex = 0 + @State private var navigationbarType: NavigationbarType = .diaryDetails + + private let detailDiaryService = DetailDiaryService.shared var body: some View { VStack(spacing: 16.scaledByWidth()) { - SwiftUINavigationView(navigationbarType: .diaryDetails, + SwiftUINavigationView(navigationbarType: navigationbarType, selectedIndex: $selectedIndex) - ScrollableDiaryView( - diaryText: diaryText, - corrections: coachingResponse.corrections, - currentIndex: currentIndex, - selectedIndex: selectedIndex, - dateText: "2023년 3월 27일 4:18PM", - authorText: "유진이" - ) + if let response = response { + ScrollableDiaryView( + diaryText: response.content, + corrections: response.corrections, + currentIndex: currentIndex, + selectedIndex: selectedIndex, + dateText: response.createdAt, + authorText: response.username + ) + } else { + if isLoading { + ProgressView("Loading...") + } else if let error = error { + Text("Error: \(error.localizedDescription)") + } + } // "코칭 ON"일 때만 표시 if selectedIndex == 1 { Spacer() - CoachingContentView(currentIndex: $currentIndex, - coachingResponse: $coachingResponse) + CoachingContentView( + currentIndex: $currentIndex, + coachingsResponse: $coachingsResponse, + coachingResponse: $coachingsResponse.corrections + ) } else { Spacer(minLength: 342.scaledByHeight()) } } + .onAppear { + Task { + await fetchCoachingData(diaryID: diaryID ?? 0) + } + } + } + + @MainActor + private func fetchCoachingData(diaryID: Int) async { + isLoading = true + do { + let response = try await detailDiaryService.getDetailDiary(diaryID: diaryID) + self.response = response + + // CoachingsResponse로 변환 + let corrections = response.corrections ?? [] + self.coachingsResponse = CoachingsResponse(corrections: corrections) + + if corrections.isEmpty { + navigationbarType = .unCoached + } + + isLoading = false + } catch { + isLoading = false + self.error = error as? SmeemError + } } } @available(iOS 17, *) #Preview { - @State var diaryText = "I watched Avatar with my boyfriend at Hongdae CGV. I should have skimmed the previous season - Avatar1.. I really couldn’t get what they weere saying and the universe(??). What I was annoyed then was 두팔 didn’t know that as me. I think 두팔 who is my boyfriend should study before wathcing…. but Avatar2 is amazing movie I think. In my personal opinion, the jjin main character of Avatar2 is not Sully, but his son." - - @State var coachingResponse = CoachingsResponse.sample - - DetailDiaryCoachedView(diaryText: $diaryText, coachingResponse: $coachingResponse) + DetailDiaryCoachedView(diaryID: .constant(0)) } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift b/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift index 99d9633b..00da1b3a 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift @@ -193,3 +193,8 @@ extension EditDiaryViewController: UITextViewDelegate { return viewController.diaryTextView.text.getArrayAfterRegex(regex: "[a-zA-z]").count > 0 } } + +@available(iOS 17, *) +#Preview { + EditDiaryViewController() +} diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Home/HomeViewController.swift b/Smeem-iOS/Smeem-iOS/Presentation/Home/HomeViewController.swift index 9b86d718..dc1be57f 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Home/HomeViewController.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Home/HomeViewController.swift @@ -5,6 +5,7 @@ // Created by 임주민 on 2023/05/05. // +import SwiftUI import UIKit import Combine @@ -253,9 +254,23 @@ final class HomeViewController: BaseViewController { } @objc func fullViewButtonDidTap(_ gesture: UITapGestureRecognizer) { - let detailDiaryVC = DetailDiaryViewController() - detailDiaryVC.diaryId = homeDiaryDict[currentDate.toString("yyyy-MM-dd")]?.diaryId ?? 0 - self.navigationController?.pushViewController(detailDiaryVC, animated: true) +// let detailDiaryVC = DetailDiaryViewController() +// detailDiaryVC.diaryId = homeDiaryDict[currentDate.toString("yyyy-MM-dd")]?.diaryId ?? 0 +// self.navigationController?.pushViewController(detailDiaryVC, animated: true) + + let diaryID = homeDiaryDict[currentDate.toString("yyyy-MM-dd")]?.diaryId ?? 0 + + @State var defaultIndex = 0 + + let detailDiaryVC = DetailDiaryCoachedView(diaryID: .constant(diaryID)) + let hostingController = UIHostingController(rootView: detailDiaryVC) + + addChild(hostingController) + hostingController.view.frame = view.bounds + view.addSubview(hostingController.view) + hostingController.didMove(toParent: self) + + self.navigationController?.pushViewController(hostingController, animated: true) } @objc func floatingViewDidTap(_ gesture: UITapGestureRecognizer) { From 0030e7167616178de0ff8362eedae1dd503d3a13 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Thu, 5 Dec 2024 12:18:32 +0900 Subject: [PATCH 04/37] =?UTF-8?q?[Chore]=20#233=20-=20=EB=84=A4=EB=B9=84?= =?UTF-8?q?=EB=B0=94=20=EC=83=81=ED=83=9C=EA=B4=80=EB=A6=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SwiftUI/SwiftUINavigationView.swift | 19 +++++++++++----- .../DetailDiary/DetailDiaryCoachedView.swift | 22 +++++++++++++++++-- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift index bc4f0740..f6b7554b 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift @@ -5,6 +5,7 @@ // Created by Joon Baek on 2024/10/18. // +import Combine import SwiftUI enum NavigationbarType { @@ -13,21 +14,27 @@ enum NavigationbarType { case unCoached } +final class NavigationViewModel: ObservableObject { + let leftButtonTapped = PassthroughSubject() + let rightButtonTapped = PassthroughSubject() +} + struct SwiftUINavigationView: View { - let navigationbarType: NavigationbarType - let options = ["코칭 OFF", "코칭 ON"] + + @ObservedObject var viewModel: NavigationViewModel @State private var showFloatingView = false @Binding var selectedIndex: Int - @Environment(\.dismiss) private var dismiss + let navigationbarType: NavigationbarType + let options = ["코칭 OFF", "코칭 ON"] var body: some View { HStack { // 뒤로가기 버튼 if navigationbarType == .diaryDetails || navigationbarType == .unCoached { Button(action: { - dismiss() + viewModel.leftButtonTapped.send() }, label: { Image("icnBack") .imageScale(.large) @@ -60,7 +67,7 @@ struct SwiftUINavigationView: View { } } else { Button(action: { - // 다른 버튼 액션 + viewModel.rightButtonTapped.send() }, label: { Text("닫기") .tint(.black) @@ -76,6 +83,6 @@ struct SwiftUINavigationView: View { @State var defaultIndex = 0 NavigationView { - SwiftUINavigationView(navigationbarType: .unCoached, selectedIndex: $defaultIndex) + SwiftUINavigationView(viewModel: NavigationViewModel(), selectedIndex: $defaultIndex, navigationbarType: .unCoached) } } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index b014fb39..32151742 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -9,6 +9,10 @@ import Combine import SwiftUI struct DetailDiaryCoachedView: View { + + @StateObject private var navigationViewModel = NavigationViewModel() + @State private var cancelBag = Set() + @State private var coachingsResponse = CoachingsResponse(corrections: []) @State private var response: DetailDiaryResponse? @State private var isLoading = false @@ -16,15 +20,29 @@ struct DetailDiaryCoachedView: View { @Binding var diaryID: Int? @State var currentIndex = 0 + @State private var isShowingFullScreen = false @State private var selectedIndex = 0 @State private var navigationbarType: NavigationbarType = .diaryDetails + @Environment(\.dismiss) private var dismiss + private let detailDiaryService = DetailDiaryService.shared var body: some View { VStack(spacing: 16.scaledByWidth()) { - SwiftUINavigationView(navigationbarType: navigationbarType, - selectedIndex: $selectedIndex) + SwiftUINavigationView(viewModel: navigationViewModel, + selectedIndex: $selectedIndex, + navigationbarType: navigationbarType + ) + .fullScreenCover(isPresented: $isShowingFullScreen) { + FloatingButtonsSwiftUIView() + } + .onReceive(navigationViewModel.leftButtonTapped) { + dismiss() + } + .onReceive(navigationViewModel.rightButtonTapped) { + isShowingFullScreen = true + } if let response = response { ScrollableDiaryView( From 32a1cbd71391932d6b12d77fccca48b3ce12802f Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Sun, 8 Dec 2024 20:06:20 +0900 Subject: [PATCH 05/37] =?UTF-8?q?[FEAT]=20#235=20-=20SwiftUI=20=EA=B8=B0?= =?UTF-8?q?=EC=A4=80=20=EB=A1=9C=EB=94=A9=EB=B7=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj | 2 +- .../SwiftUI}/HighlightModifier.swift | 0 .../DiaryComplete/CoachingStore.swift | 2 + .../DiaryComplete/CoachingView.swift | 160 +++++++++--------- .../DiaryComplete/SmemeLoadingView.swift | 26 +++ 5 files changed, 113 insertions(+), 77 deletions(-) rename Smeem-iOS/Smeem-iOS/Global/{ => Extensions/SwiftUI}/HighlightModifier.swift (100%) create mode 100644 Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeLoadingView.swift diff --git a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj index 54476ff4..9eddff69 100644 --- a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj +++ b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj @@ -574,6 +574,7 @@ 373D29912CBFE16B00A559A3 /* SwiftUI */ = { isa = PBXGroup; children = ( + 377B3BEF2CF613710086E0BC /* HighlightModifier.swift */, 373D29922CBFE17B00A559A3 /* View+.swift */, ); path = SwiftUI; @@ -618,7 +619,6 @@ 37A574B929FE209F00312453 /* Resources */, 4AC4B82B2A2F9F5300E147AA /* Constants */, 37EB69E42A4B3B6B00075E4E /* Protocols */, - 377B3BEF2CF613710086E0BC /* HighlightModifier.swift */, ); path = Global; sourceTree = ""; diff --git a/Smeem-iOS/Smeem-iOS/Global/HighlightModifier.swift b/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/HighlightModifier.swift similarity index 100% rename from Smeem-iOS/Smeem-iOS/Global/HighlightModifier.swift rename to Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/HighlightModifier.swift diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingStore.swift b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingStore.swift index 959b925e..dffa541a 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingStore.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingStore.swift @@ -49,9 +49,11 @@ final class CoachingStore: Store, ObservableObject { do { state.detailDiaryResponse = try await service.detailDiaryAPI(diaryID: ID) state.isEnabled = state.detailDiaryResponse.correctionMaxCount-state.detailDiaryResponse.correctionCount == 0 ? false : true + state.isLoadingView = false } catch let error { let error = error as? SmeemError state.toastErrorMessage = error + state.isLoadingView = false } } case .coachingButton(let ID): diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingView.swift index 2e1f211e..85749905 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingView.swift @@ -13,88 +13,96 @@ struct CoachingView: View { @StateObject var store: CoachingStore var body: some View { - - if store.state.hiddenIndex != 1 { - HStack() { - Spacer() - Button(action: { - let homeVC = HomeViewController() - homeVC.handlePostDiaryAPI(with: store.state.diaryResponse) - changeRootViewController(homeVC) - }, - label: { - Text("닫기") - .tint(.black) - }) - .padding(.trailing, 18) - } - .frame(height: 66) - } - - // MARK: 일기 작성 완료 화면 - if store.state.hiddenIndex == 0 { - Button(action: { - if store.state.isEnabled { - store.send(action: .coachingButton(diaryID: store.state.diaryResponse.diaryID)) - } - }) { - HStack { - Image("icnCrownMono") - .frame(width: 24, height: 24) - Text("하루 한 번 무료 AI 코칭") - .font(Font.custom("Pretendard", size: 16).weight(.bold)) - .lineSpacing(0.19) - .foregroundColor(.white) + // MARK: 네비뷰 + VStack { + if store.state.hiddenIndex != 1 { + HStack() { + Spacer() + Button(action: { + let homeVC = HomeViewController() + homeVC.handlePostDiaryAPI(with: store.state.diaryResponse) + changeRootViewController(homeVC) + }, + label: { + Text("닫기") + .tint(.black) + }) + .padding(.trailing, 18) + } + .frame(height: 66) } - } - .disabled(!store.state.isEnabled) - .frame(width: screenWidth-32, height: 48, alignment: .center) - .background { - if store.state.isEnabled { - LinearGradient( - stops: [ - Gradient.Stop(color: Color(red: 1, green: 0, blue: 0.02).opacity(0.2), location: 0.00), - Gradient.Stop(color: .white.opacity(0.2), location: 0.28), - Gradient.Stop(color: .white.opacity(0.2), location: 0.83), - Gradient.Stop(color: Color(red: 1, green: 0, blue: 0.02).opacity(0.2), location: 1.00), - ], - startPoint: UnitPoint(x: 0.15, y: -1.24), - endPoint: UnitPoint(x: 0.72, y: 3.4) - ) + + // MARK: 일기 작성 완료 화면 + if store.state.hiddenIndex == 0 { + Button(action: { + if store.state.isEnabled { + store.send(action: .coachingButton(diaryID: store.state.diaryResponse.diaryID)) + } + }) { + HStack { + Image("icnCrownMono") + .frame(width: 24, height: 24) + Text("하루 한 번 무료 AI 코칭") + .font(Font.custom("Pretendard", size: 16).weight(.bold)) + .lineSpacing(0.19) + .foregroundColor(.white) + } + } + .disabled(!store.state.isEnabled) + .frame(width: screenWidth-32, height: 48, alignment: .center) + .background { + if store.state.isEnabled { + LinearGradient( + stops: [ + Gradient.Stop(color: Color(red: 1, green: 0, blue: 0.02).opacity(0.2), location: 0.00), + Gradient.Stop(color: .white.opacity(0.2), location: 0.28), + Gradient.Stop(color: .white.opacity(0.2), location: 0.83), + Gradient.Stop(color: Color(red: 1, green: 0, blue: 0.02).opacity(0.2), location: 1.00), + ], + startPoint: UnitPoint(x: 0.15, y: -1.24), + endPoint: UnitPoint(x: 0.72, y: 3.4) + ) + } + } + .background(store.state.isEnabled ? Color(UIColor.point) : Color(UIColor.gray400)) + .cornerRadius(5) + + DiaryDetailView(diaryInformation: $store.state.detailDiaryResponse) + + Spacer() + + // MARK: 로티 화면 + } else if store.state.hiddenIndex == 1 { + VStack { + LottieView("smeemLoading") + .loopMode(.loop) + .frame(width: screenWidth, height: 164, alignment: .center) + + Text("AI 코치가 내 일기를 분석하고 있어요\n잠시만 기다려주세요") + .font(Font.custom("Pretendard", size: 16)) + .multilineTextAlignment(.center) + .foregroundColor(.black) + } + + // MARK: 첨삭 화면 + } else { + CoachingCompleteView(diaryText: $store.state.detailDiaryResponse.content, + coachingAppData: $store.state.coachingAppData) } + + // MARK: 첫 진입시 토스트뷰 실행 + SmemeToastView(type: $store.state.toastMessage) + SmeemErrorToastView(type: $store.state.toastErrorMessage) } - .background(store.state.isEnabled ? Color(UIColor.point) : Color(UIColor.gray400)) - .cornerRadius(5) - - DiaryDetailView(diaryInformation: $store.state.detailDiaryResponse) - .onAppear { - store.send(action: .detailDiaryAPI(diaryID: store.state.diaryResponse.diaryID)) + .overlay(alignment: .center) { + // MARK: 최상단바에 로딩뷰 + if store.state.isLoadingView { + SmemeLoadingView() } - - Spacer() - - // MARK: 로티 화면 - } else if store.state.hiddenIndex == 1 { - VStack { - LottieView("smeemLoading") - .loopMode(.loop) - .frame(width: screenWidth, height: 164, alignment: .center) - - Text("AI 코치가 내 일기를 분석하고 있어요\n잠시만 기다려주세요") - .font(Font.custom("Pretendard", size: 16)) - .multilineTextAlignment(.center) - .foregroundColor(.black) } - - // MARK: 첨삭 화면 - } else { - CoachingCompleteView(diaryText: $store.state.detailDiaryResponse.content, - coachingAppData: $store.state.coachingAppData) + .onAppear() { + store.send(action: .detailDiaryAPI(diaryID: store.state.diaryResponse.diaryID)) } - - // MARK: 첫 진입시 토스트뷰 실행 - SmemeToastView(type: $store.state.toastMessage) - SmeemErrorToastView(type: $store.state.toastErrorMessage) } } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeLoadingView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeLoadingView.swift new file mode 100644 index 00000000..4fec1bae --- /dev/null +++ b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeLoadingView.swift @@ -0,0 +1,26 @@ +// +// SmemeLoadingView.swift +// Smeem-iOS +// +// Created by 황찬미 on 11/26/24. +// + +import SwiftUI + +struct SmemeLoadingView: View { + + var body: some View { + HStack { + Spacer() + VStack { + Spacer() + ProgressView() + Spacer() + } + Spacer() + } + .ignoresSafeArea() + .background(Color.white.opacity(0.1)) // 반투명 배경 + .allowsHitTesting(true) // 로딩 중 터치 차단 + } +} From 4105d0d4218b03441fda395c055dfcead1d46f3d Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Sun, 8 Dec 2024 20:47:32 +0900 Subject: [PATCH 06/37] =?UTF-8?q?[FEAT]=20#235=20-=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EC=A0=84=ED=99=98=20=ED=9B=84=20=EB=B2=84=ED=8A=BC=EC=83=89=20?= =?UTF-8?q?=EB=B0=94=EB=80=8C=EB=8A=94=20=ED=98=84=EC=83=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/DiaryComplete/CoachingView.swift | 3 ++- .../Presentation/DiaryComplete/SmemeLoadingView.swift | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingView.swift index 85749905..83745c89 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingView.swift @@ -97,12 +97,13 @@ struct CoachingView: View { .overlay(alignment: .center) { // MARK: 최상단바에 로딩뷰 if store.state.isLoadingView { + SmemeEmptyView() SmemeLoadingView() } } .onAppear() { store.send(action: .detailDiaryAPI(diaryID: store.state.diaryResponse.diaryID)) - } + } } } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeLoadingView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeLoadingView.swift index 4fec1bae..a59a2526 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeLoadingView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeLoadingView.swift @@ -24,3 +24,13 @@ struct SmemeLoadingView: View { .allowsHitTesting(true) // 로딩 중 터치 차단 } } + +struct SmemeEmptyView: View { + + var body: some View { + ZStack { + Color.white.ignoresSafeArea() + } + .animation(.easeInOut(duration: 0.5), value: true) // 0.5초 뒤에 서서히 사라짐 + } +} From 2079066203ed1d12257513cfa3974858280011b7 Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Sun, 8 Dec 2024 20:50:40 +0900 Subject: [PATCH 07/37] =?UTF-8?q?[CHORE]=20#235=20-=20=EC=BD=94=EC=B9=AD?= =?UTF-8?q?=20=ED=9B=84=20=EB=B3=80=EA=B2=BD=EB=90=9C=20=ED=85=8D=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/DiaryComplete/CoachingStore.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingStore.swift b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingStore.swift index dffa541a..4e9966d4 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingStore.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingStore.swift @@ -76,13 +76,13 @@ final class CoachingStore: Store, ObservableObject { func correctTextResult(_ count: Int) -> String { switch count { case 0: - return "완벽한 일기예요! 문장이 자연스럽고 오류가 없어요" + return "완벽한 일기예요!👍\n문장이 자연스럽고 오류가 없어요" case 1: - return "잘 작성했어요! 작은 부분만 다듬으면 완벽해요" + return "잘 작성했어요!🙌\n작은 부분만 다듬으면 완벽해요" case 2...: - return "대단해요! 몇가지 피드백을 준비해봤어요." + return "대단해요!🥳🎉\n몇 가지 피드백을 준비해 봤어요." default: - return "대단해요! 몇가지 피드백을 준비해봤어요." + return "대단해요!🥳🎉\n몇 가지 피드백을 준비해 봤어요." } } } From 53c52a75178c2b7a016e8155cefdfebd4005b70b Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Sun, 8 Dec 2024 20:54:42 +0900 Subject: [PATCH 08/37] =?UTF-8?q?[CHORE]=20#235=20-=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj | 15 ++++++++++++--- .../LoadingView}/SmemeLoadingView.swift | 0 .../SmeemComponent/Toast}/SmemeToastView.swift | 0 .../View}/CoachingView.swift | 2 +- .../CoachingCompleteView.swift | 0 .../DiaryDetailView.swift | 0 .../{DiaryComplete => Store}/CoachingStore.swift | 0 7 files changed, 13 insertions(+), 4 deletions(-) rename Smeem-iOS/Smeem-iOS/{Presentation/DiaryComplete => Global/UIComponents/SmeemComponent/LoadingView}/SmemeLoadingView.swift (100%) rename Smeem-iOS/Smeem-iOS/{Presentation/DiaryComplete => Global/UIComponents/SmeemComponent/Toast}/SmemeToastView.swift (100%) rename Smeem-iOS/Smeem-iOS/Presentation/{DiaryComplete => Coaching/View}/CoachingView.swift (99%) rename Smeem-iOS/Smeem-iOS/Presentation/{Coaching => Components}/CoachingCompleteView.swift (100%) rename Smeem-iOS/Smeem-iOS/Presentation/{DiaryComplete => Components}/DiaryDetailView.swift (100%) rename Smeem-iOS/Smeem-iOS/Presentation/{DiaryComplete => Store}/CoachingStore.swift (100%) diff --git a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj index 9eddff69..8cfdedeb 100644 --- a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj +++ b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj @@ -462,6 +462,10 @@ /* Begin PBXFileSystemSynchronizedRootGroup section */ 377B3BF12CF618B90086E0BC /* SwiftUI */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = SwiftUI; sourceTree = ""; }; + 4A17370E2D05C02E00B772C3 /* Toast */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Toast; sourceTree = ""; }; + 4A17370F2D05C03600B772C3 /* LoadingView */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = LoadingView; sourceTree = ""; }; + 4A1737152D05C06E00B772C3 /* Components */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Components; sourceTree = ""; }; + 4A1737192D05C07100B772C3 /* Store */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Store; sourceTree = ""; }; 4AB3494D2CF229D10047C484 /* UIViewConponent */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (370BD0B62CFB660C009560DB /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = UIViewConponent; sourceTree = ""; }; 4AB3494E2CF22A070047C484 /* Global */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Global; sourceTree = ""; }; 4AB3494F2CF22A250047C484 /* Button */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Button; sourceTree = ""; }; @@ -473,7 +477,6 @@ 4AB349BA2CF23B770047C484 /* Coaching */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Coaching; sourceTree = ""; }; 4AB349BC2CF23D210047C484 /* Coaching */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Coaching; sourceTree = ""; }; 4AF050CE2CE9DE010055BC3F /* Coaching */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Coaching; sourceTree = ""; }; - 4AF050D72CEA01E20055BC3F /* DiaryComplete */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = DiaryComplete; sourceTree = ""; }; 4AF050D82CEA01EA0055BC3F /* Coaching */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Coaching; sourceTree = ""; }; /* End PBXFileSystemSynchronizedRootGroup section */ @@ -627,7 +630,8 @@ isa = PBXGroup; children = ( 4AF050D82CEA01EA0055BC3F /* Coaching */, - 4AF050D72CEA01E20055BC3F /* DiaryComplete */, + 4A1737192D05C07100B772C3 /* Store */, + 4A1737152D05C06E00B772C3 /* Components */, 4AC047232A8FCA9700EBDC0E /* AuthManagement */, 4AA6FEE72C3ABD7C00E588E9 /* ResignSummray */, 4AA5E4B52BF24CEB00F308C8 /* BadgeBottomSheet */, @@ -1018,6 +1022,8 @@ 4A1EE9552A4DFB86007BFEF3 /* SmeemComponent */ = { isa = PBXGroup; children = ( + 4A17370F2D05C03600B772C3 /* LoadingView */, + 4A17370E2D05C02E00B772C3 /* Toast */, 4AB349502CF22A2E0047C484 /* TextView */, 4AB3494F2CF22A250047C484 /* Button */, 4AB3494E2CF22A070047C484 /* Global */, @@ -1752,6 +1758,10 @@ ); fileSystemSynchronizedGroups = ( 377B3BF12CF618B90086E0BC /* SwiftUI */, + 4A17370E2D05C02E00B772C3 /* Toast */, + 4A17370F2D05C03600B772C3 /* LoadingView */, + 4A1737152D05C06E00B772C3 /* Components */, + 4A1737192D05C07100B772C3 /* Store */, 4AB3494D2CF229D10047C484 /* UIViewConponent */, 4AB3494E2CF22A070047C484 /* Global */, 4AB3494F2CF22A250047C484 /* Button */, @@ -1762,7 +1772,6 @@ 4AB349562CF22BFF0047C484 /* EditUser */, 4AB349BA2CF23B770047C484 /* Coaching */, 4AF050CE2CE9DE010055BC3F /* Coaching */, - 4AF050D72CEA01E20055BC3F /* DiaryComplete */, 4AF050D82CEA01EA0055BC3F /* Coaching */, ); name = "Smeem-iOS"; diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeLoadingView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SmeemComponent/LoadingView/SmemeLoadingView.swift similarity index 100% rename from Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeLoadingView.swift rename to Smeem-iOS/Smeem-iOS/Global/UIComponents/SmeemComponent/LoadingView/SmemeLoadingView.swift diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeToastView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SmeemComponent/Toast/SmemeToastView.swift similarity index 100% rename from Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/SmemeToastView.swift rename to Smeem-iOS/Smeem-iOS/Global/UIComponents/SmeemComponent/Toast/SmemeToastView.swift diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/View/CoachingView.swift similarity index 99% rename from Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingView.swift rename to Smeem-iOS/Smeem-iOS/Presentation/Coaching/View/CoachingView.swift index 83745c89..28d4c25b 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/View/CoachingView.swift @@ -103,7 +103,7 @@ struct CoachingView: View { } .onAppear() { store.send(action: .detailDiaryAPI(diaryID: store.state.diaryResponse.diaryID)) - } + } } } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/CoachingCompleteView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Components/CoachingCompleteView.swift similarity index 100% rename from Smeem-iOS/Smeem-iOS/Presentation/Coaching/CoachingCompleteView.swift rename to Smeem-iOS/Smeem-iOS/Presentation/Components/CoachingCompleteView.swift diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/DiaryDetailView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Components/DiaryDetailView.swift similarity index 100% rename from Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/DiaryDetailView.swift rename to Smeem-iOS/Smeem-iOS/Presentation/Components/DiaryDetailView.swift diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingStore.swift b/Smeem-iOS/Smeem-iOS/Presentation/Store/CoachingStore.swift similarity index 100% rename from Smeem-iOS/Smeem-iOS/Presentation/DiaryComplete/CoachingStore.swift rename to Smeem-iOS/Smeem-iOS/Presentation/Store/CoachingStore.swift From 540f4c35e8f630fb5c30b5b77805f24ef496d097 Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Sun, 8 Dec 2024 21:30:52 +0900 Subject: [PATCH 09/37] =?UTF-8?q?[DELETE]=20#235=20-=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj | 17 ----- .../SwiftUI/CoachingComparisonView.swift | 48 ++++++------ .../CoachingCompletedView.swift | 38 ---------- .../CoachingExplanationView.swift | 38 ---------- .../CustomSegmentedControl.swift | 74 ------------------- .../SwiftUINavigationView.swift | 42 ----------- .../Components/CoachingCompleteView.swift | 33 ++++++--- 7 files changed, 43 insertions(+), 247 deletions(-) delete mode 100644 Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CoachingCompletedView.swift delete mode 100644 Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CoachingExplanationView.swift delete mode 100644 Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CustomSegmentedControl.swift delete mode 100644 Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/SwiftUINavigationView.swift diff --git a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj index 8cfdedeb..0169dc70 100644 --- a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj +++ b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj @@ -446,27 +446,12 @@ A3D7ECB62A26566A009857D6 /* EditNicknameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditNicknameViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ -/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - 370BD0B62CFB660C009560DB /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - CoachingComparisonView.swift, - CoachingCompletedView.swift, - CoachingExplanationView.swift, - CustomSegmentedControl.swift, - SwiftUINavigationView.swift, - ); - target = 4A8FFA4B29C9E1FD00FB76C0 /* Smeem-iOS */; - }; -/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ - /* Begin PBXFileSystemSynchronizedRootGroup section */ 377B3BF12CF618B90086E0BC /* SwiftUI */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = SwiftUI; sourceTree = ""; }; 4A17370E2D05C02E00B772C3 /* Toast */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Toast; sourceTree = ""; }; 4A17370F2D05C03600B772C3 /* LoadingView */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = LoadingView; sourceTree = ""; }; 4A1737152D05C06E00B772C3 /* Components */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Components; sourceTree = ""; }; 4A1737192D05C07100B772C3 /* Store */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Store; sourceTree = ""; }; - 4AB3494D2CF229D10047C484 /* UIViewConponent */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (370BD0B62CFB660C009560DB /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = UIViewConponent; sourceTree = ""; }; 4AB3494E2CF22A070047C484 /* Global */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Global; sourceTree = ""; }; 4AB3494F2CF22A250047C484 /* Button */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Button; sourceTree = ""; }; 4AB349502CF22A2E0047C484 /* TextView */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = TextView; sourceTree = ""; }; @@ -678,7 +663,6 @@ isa = PBXGroup; children = ( 377B3BF12CF618B90086E0BC /* SwiftUI */, - 4AB3494D2CF229D10047C484 /* UIViewConponent */, 371107DB2ACAB4E3007A4AC2 /* Base */, 4A1EE9552A4DFB86007BFEF3 /* SmeemComponent */, ); @@ -1762,7 +1746,6 @@ 4A17370F2D05C03600B772C3 /* LoadingView */, 4A1737152D05C06E00B772C3 /* Components */, 4A1737192D05C07100B772C3 /* Store */, - 4AB3494D2CF229D10047C484 /* UIViewConponent */, 4AB3494E2CF22A070047C484 /* Global */, 4AB3494F2CF22A250047C484 /* Button */, 4AB349502CF22A2E0047C484 /* TextView */, diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingComparisonView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingComparisonView.swift index 1de1dbdd..586d08df 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingComparisonView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingComparisonView.swift @@ -7,28 +7,28 @@ import SwiftUI +import SwiftUI + struct CoachingComparisonView: View { @Binding var coachingResponse: CoachingResponse - @State private var textHeight: CGFloat = 0 // Text의 높이를 저장할 변수 var body: some View { VStack(spacing: 20) { VStack(alignment: .leading, spacing: 8) { - HStack { - Rectangle() - .frame(width: 2, height: textHeight) - .foregroundStyle(Color(UIColor.black)) + HStack(spacing: 8) { + + GeometryReader { geomerty in + Rectangle() + .frame(height: geomerty.size.height) + .foregroundStyle(Color(UIColor.black)) + } + .frame(width: 2) Text("나의 일기") .font(Font.custom("Pretendard", size: 16).weight(.medium)) .foregroundColor(Color(UIColor.black)) - .background(GeometryReader { geometry in - Color.clear - .preference(key: TextHeightPreferenceKey.self, value: geometry.size.height) - }) - } - .onPreferenceChange(TextHeightPreferenceKey.self) { value in - textHeight = value + + Spacer() } Text(coachingResponse.originalSentence) @@ -39,14 +39,19 @@ struct CoachingComparisonView: View { .padding(.trailing, 18) VStack(alignment: .leading, spacing: 8) { - HStack { - Rectangle() - .frame(width: 2, height: textHeight) - .foregroundStyle(Color(UIColor.point)) + HStack(spacing: 8) { + GeometryReader { geomerty in + Rectangle() + .frame(height: geomerty.size.height) + .foregroundStyle(Color(UIColor.point)) + } + .frame(width: 2) Text("고친 문장") .font(Font.custom("Pretendard", size: 16).weight(.medium)) .foregroundColor(Color(UIColor.point)) + + Spacer() } Text(coachingResponse.correctedSentence) @@ -59,14 +64,3 @@ struct CoachingComparisonView: View { } } } - -struct TextHeightPreferenceKey: PreferenceKey { - static var defaultValue: CGFloat = 0 - static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { - value = nextValue() - } -} - -//#Preview { -// CoachingComparisonView() -//} diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CoachingCompletedView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CoachingCompletedView.swift deleted file mode 100644 index 55199b66..00000000 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CoachingCompletedView.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// CoachingTextView.swift -// Smeem-iOS -// -// Created by Joon Baek on 2024/10/16. -// - -import SwiftUI - -struct CoachingTextView: View { - @Binding var coachingText: String - - var body: some View { - - VStack(spacing: 16) { - Text("일기를 잘 작성하셨어요! \n내용이 명확하고 흥미로웠습니다.\n이제 몇 가지 문법적 오류를 수정해 볼까요?") - .font(Font.custom("Pretendard", size: 16)) - // Colors 상수 등록 필요 - .foregroundColor(Color(UIColor.smeemBlack)) - .frame(maxWidth: .infinity, alignment: .leading) - - ScrollView { - Text(coachingText) - .font(Font.custom("Pretendard", size: 16)) - .foregroundColor(Color(UIColor.gray400)) - .lineSpacing(0.375) - } - - Spacer() - } - .padding(.horizontal, screenWidth * 0.048) - } -} -// -//@available (iOS 17, *) -//#Preview { -// CoachingTextView(coachingText: "") -//} diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CoachingExplanationView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CoachingExplanationView.swift deleted file mode 100644 index 8686a472..00000000 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CoachingExplanationView.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// CoachingExplanationView.swift -// Smeem-iOS -// -// Created by 황찬미 on 11/16/24. -// - -import SwiftUI - -struct CoachingExplanationView: View { - @Binding var coachingResponse: CoachingResponse - - var body: some View { - HStack() { - - ZStack(alignment: .leading) { - GeometryReader { geomerty in - Rectangle() - .fill(Color(UIColor.gray100)) - .frame(height: geomerty.size.height) - .cornerRadius(3) - } - - Text(coachingResponse.reason) - .font(Font.custom("Pretendard", size: 14).weight(.regular)) - .foregroundStyle(.black) - .padding(12) - } - .fixedSize(horizontal: false, vertical: true) - .padding(.leading, 18) - .padding(.trailing, 18) - } - } -} - -//#Preview { -// CoachingExplanationView() -//} diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CustomSegmentedControl.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CustomSegmentedControl.swift deleted file mode 100644 index 9576441a..00000000 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/CustomSegmentedControl.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// CustomSegmentedControl.swift -// Smeem-iOS -// -// Created by Joon Baek on 2024/10/22. -// - -import SwiftUI - -struct CustomSegmentedControl: View { - @Binding var selectedIndex: Int - let options: [String] - - var body: some View { - HStack(spacing: 0) { - ForEach(options.indices, id: \.self) { index in - SegmentButton( - title: options[index], - isSelected: selectedIndex == index, - action: { selectedIndex = index } - ) - } - } - .background(Color.gray.opacity(0.2)) - .cornerRadius(8) - } -} - -struct SegmentButton: View { - let title: String - let isSelected: Bool - let action: () -> Void - - var body: some View { - Button(action: action) { - Text(title) - .padding(.vertical, 8) - .padding(.horizontal, 11) - .frame(maxWidth: .infinity) - .background(backgroundColor) - .foregroundColor(foregroundColor) - .font(Font(UIFont.c5)) - } - } - - private var backgroundColor: Color { - isSelected ? (isCoachingOn ? Color(UIColor.point) : Color(UIColor.gray200)) : Color(UIColor.gray100) - } - - private var foregroundColor: Color { - isSelected ? .white : Color(UIColor.gray500) - } - - private var isCoachingOn: Bool { - title == "코칭 ON" - } -} - -struct PreviewWrapper: View { - @State private var selectedIndex = 0 - let options = ["코칭 OFF", "코칭 ON"] - - var body: some View { - CustomSegmentedControl(selectedIndex: $selectedIndex, options: options) - .frame(height: 40) - .padding(117) - } -} - -@available(iOS 17.0, *) -#Preview { - PreviewWrapper() -} - diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/SwiftUINavigationView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/SwiftUINavigationView.swift deleted file mode 100644 index 0c80a744..00000000 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/UIViewConponent/SwiftUINavigationView.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// SwiftUINavigationView.swift -// Smeem-iOS -// -// Created by Joon Baek on 2024/10/18. -// - -import SwiftUI - -struct SwiftUINavigationView: View { - @State private var selectedIndex = 0 - let options = ["코칭 OFF", "코칭 ON"] - - var body: some View { - HStack() { - Button(action: /*@START_MENU_TOKEN@*/{}/*@END_MENU_TOKEN@*/, - label: { - Image("icnBack") - .imageScale(.large) - }) - .padding(.leading, 10) - -// CustomSegmentedControl(selectedIndex: $selectedIndex, options: options) -// .frame(height: 32) -// .padding(65) - - Spacer() - - Button(action: /*@START_MENU_TOKEN@*/{}/*@END_MENU_TOKEN@*/, - label: { - Text("닫기") - .tint(.black) - }) - .padding(.trailing, 18) - } - .frame(height: 66) - } -} - -#Preview { - SwiftUINavigationView() -} diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Components/CoachingCompleteView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Components/CoachingCompleteView.swift index e22388f9..38e3bca9 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Components/CoachingCompleteView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Components/CoachingCompleteView.swift @@ -18,23 +18,34 @@ struct CoachingCompleteView: View { VStack(spacing: 15) { VStack(spacing: 16) { ScrollView { - HStack { - Text(diaryText) - .modifier(HighlightModifier( - diaryText: diaryText, - corrections: coachingAppData.corrections, - highlightIndex: currentIndex - )) - .font(Font.custom("Pretendard", size: 16)) - .foregroundColor(Color(UIColor.gray400)) - .lineSpacing(0.375) + VStack(spacing: 16) { + HStack { + Text(coachingAppData.correctResultText) + .font(Font.custom("Pretendard", size: 16)) + .foregroundColor(Color(UIColor.black)) + .lineSpacing(0.375) + Spacer() + } - Spacer() + HStack { + Text(diaryText) + .modifier(HighlightModifier( + diaryText: diaryText, + corrections: coachingAppData.corrections, + highlightIndex: currentIndex + )) + .font(Font.custom("Pretendard", size: 16)) + .foregroundColor(Color(UIColor.gray400)) + .lineSpacing(0.375) + + Spacer() + } } } Spacer() } + .padding(.top) .padding(.horizontal, screenWidth * 0.048) VStack(spacing: 20) { From f7bdf5859e04590f49fc8d9a3fd34d4136f79fc4 Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Sun, 8 Dec 2024 22:10:35 +0900 Subject: [PATCH 10/37] =?UTF-8?q?[CHORE]=20#235=20-=20yml=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/smeemDev.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/smeemDev.yml b/.github/workflows/smeemDev.yml index e1d4a674..ca303b36 100644 --- a/.github/workflows/smeemDev.yml +++ b/.github/workflows/smeemDev.yml @@ -6,6 +6,8 @@ name: Swift on: push: branches: [ "develop" ] + pull_request: + branches: [ "develop" ] jobs: build: From aac631302d54b301d8ba835a15524aa276e5192a Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Mon, 9 Dec 2024 23:28:45 +0900 Subject: [PATCH 11/37] =?UTF-8?q?[Feat]=20#233=20-=20EditDiaryView=20?= =?UTF-8?q?=EB=9E=98=ED=95=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Global/Extensions/SwiftUI/View+.swift | 22 ++++++++ .../SwiftUI/FloatingButtonsSwiftUIView.swift | 20 +++++-- .../SwiftUI/SwiftUINavigationView.swift | 15 ++--- .../DetailDiary/DetailDiaryCoachedView.swift | 55 ++++++++++++++++--- .../Controllers/EditDiaryViewController.swift | 2 +- 5 files changed, 90 insertions(+), 24 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift b/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift index d4b33996..3d34934d 100644 --- a/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift +++ b/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift @@ -27,4 +27,26 @@ extension View { window.rootViewController = rootVC }) } + + func pushToUIKitView(_ viewController: UIViewController, dismissFullScreenCover: Bool = true) { + // 현재 presenting된 view controller + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let rootViewController = windowScene.windows.first?.rootViewController { + + // 현재 최상위 view controller (fullScreenCover 아래의 view controller) + var topViewController = rootViewController + while let presentedViewController = topViewController.presentedViewController { + topViewController = presentedViewController + } + + if let navigationController = topViewController as? UINavigationController { + navigationController.pushViewController(viewController, animated: true) + + if dismissFullScreenCover, + let presentingView = topViewController.presentingViewController { + presentingView.dismiss(animated: false, completion: nil) + } + } + } + } } diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift index 60801039..f064a577 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift @@ -5,9 +5,17 @@ // Created by Joon Baek on 11/26/24. // +import Combine import SwiftUI +final class FloatingButtonsViewModel: ObservableObject { + private(set) var editButtonTapped = PassthroughSubject() + private(set) var deleteButtonTapped = PassthroughSubject() +} + struct FloatingButtonsSwiftUIView: View { + @ObservedObject var viewModel: FloatingButtonsViewModel + @Environment(\.dismiss) var dismiss @State private var showAlert = false @@ -34,9 +42,11 @@ struct FloatingButtonsSwiftUIView: View { } .alert("수정시 모든 코칭 내용이 사라집니다. 그래도 수정하시겠습니까?", isPresented: $showAlert) { - Button("취소", role: .cancel) { dismiss() } - Button("확인", role: .destructive) { - print("수정 확인 버튼 액션") + Button("취소") { + dismiss() + } + Button("확인") { + viewModel.editButtonTapped.send() } } @@ -45,7 +55,7 @@ struct FloatingButtonsSwiftUIView: View { .background(Color.gray.opacity(0.5)) Button(action: { - + viewModel.deleteButtonTapped.send() }) { Text("삭제하기") .font(.headline) @@ -78,5 +88,5 @@ struct FloatingButtonsSwiftUIView: View { } #Preview { - FloatingButtonsSwiftUIView() + FloatingButtonsSwiftUIView(viewModel: FloatingButtonsViewModel()) } diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift index f6b7554b..6a9a7a3b 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift @@ -21,9 +21,7 @@ final class NavigationViewModel: ObservableObject { struct SwiftUINavigationView: View { - @ObservedObject var viewModel: NavigationViewModel - - @State private var showFloatingView = false + @ObservedObject var navigationViewModel: NavigationViewModel @Binding var selectedIndex: Int let navigationbarType: NavigationbarType @@ -34,7 +32,7 @@ struct SwiftUINavigationView: View { // 뒤로가기 버튼 if navigationbarType == .diaryDetails || navigationbarType == .unCoached { Button(action: { - viewModel.leftButtonTapped.send() + navigationViewModel.leftButtonTapped.send() }, label: { Image("icnBack") .imageScale(.large) @@ -57,17 +55,14 @@ struct SwiftUINavigationView: View { // 오른쪽 버튼 if navigationbarType == .diaryDetails || navigationbarType == .unCoached { Button(action: { - showFloatingView = true + navigationViewModel.rightButtonTapped.send() }, label: { Image("icnMore") }) .padding(.trailing, 18.scaledByWidth()) - .fullScreenCover(isPresented: $showFloatingView) { - FloatingButtonsSwiftUIView() - } } else { Button(action: { - viewModel.rightButtonTapped.send() + navigationViewModel.rightButtonTapped.send() }, label: { Text("닫기") .tint(.black) @@ -83,6 +78,6 @@ struct SwiftUINavigationView: View { @State var defaultIndex = 0 NavigationView { - SwiftUINavigationView(viewModel: NavigationViewModel(), selectedIndex: $defaultIndex, navigationbarType: .unCoached) + SwiftUINavigationView(navigationViewModel: NavigationViewModel(), selectedIndex: $defaultIndex, navigationbarType: .unCoached) } } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index 32151742..091c8867 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -7,6 +7,7 @@ import Combine import SwiftUI +import UIKit struct DetailDiaryCoachedView: View { @@ -19,8 +20,10 @@ struct DetailDiaryCoachedView: View { @State private var error: SmeemError? @Binding var diaryID: Int? + @State var diaryContent = "" + @State var randomTopic = "" @State var currentIndex = 0 - @State private var isShowingFullScreen = false + @State private var isShowingFloatingButtons = false @State private var selectedIndex = 0 @State private var navigationbarType: NavigationbarType = .diaryDetails @@ -30,18 +33,29 @@ struct DetailDiaryCoachedView: View { var body: some View { VStack(spacing: 16.scaledByWidth()) { - SwiftUINavigationView(viewModel: navigationViewModel, + SwiftUINavigationView(navigationViewModel: navigationViewModel, selectedIndex: $selectedIndex, navigationbarType: navigationbarType ) - .fullScreenCover(isPresented: $isShowingFullScreen) { - FloatingButtonsSwiftUIView() - } .onReceive(navigationViewModel.leftButtonTapped) { dismiss() } .onReceive(navigationViewModel.rightButtonTapped) { - isShowingFullScreen = true + isShowingFloatingButtons = true + print("눌림?") + } + .confirmationDialog("", isPresented: $isShowingFloatingButtons) { + Button("수정하기", role: .none) { + showEditConfirmation() + } + + Button("삭제하기", role: .destructive) { +// performDelete() + } + + Button("취소", role: .cancel) { + isShowingFloatingButtons = false + } } if let response = response { @@ -75,19 +89,44 @@ struct DetailDiaryCoachedView: View { } .onAppear { Task { - await fetchCoachingData(diaryID: diaryID ?? 0) + await fetchCoachingData(diaryID: diaryID ?? 0) } } } + private func showEditConfirmation() { + let alert = UIAlertController( + title: "수정 확인", + message: "수정시 모든 코칭 내용이 사라집니다. 그래도 수정하시겠습니까?", + preferredStyle: .alert + ) + + alert.addAction(UIAlertAction(title: "취소", style: .cancel)) + alert.addAction(UIAlertAction(title: "확인", style: .default) { _ in + navigateToEditDiary() + }) + + UIApplication.shared.windows.first?.rootViewController?.present(alert, animated: true) + } + + private func navigateToEditDiary() { + let editVC = EditDiaryViewController() + editVC.diaryID = self.diaryID ?? 0 + editVC.randomContent = self.randomTopic + editVC.diaryTextView.text = self.diaryContent + editVC.randomSubjectView.setData(contentText: self.randomTopic) + self.pushToUIKitView(editVC) + } + @MainActor private func fetchCoachingData(diaryID: Int) async { isLoading = true do { let response = try await detailDiaryService.getDetailDiary(diaryID: diaryID) self.response = response + self.diaryContent = response.content + self.randomTopic = response.topic - // CoachingsResponse로 변환 let corrections = response.corrections ?? [] self.coachingsResponse = CoachingsResponse(corrections: corrections) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift b/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift index 00da1b3a..6cf7a7c9 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift @@ -48,7 +48,7 @@ final class EditDiaryViewController: BaseViewController { lazy var diaryTextView: UITextView = { let textView = UITextView() - textView.text = "dafd???" + textView.text = "목데이터" textView.configureDiaryTextView(topInset: 20) textView.configureAttributedText() textView.delegate = self From 34f48c7cb00789bf5a19fab926a27061903014c5 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Tue, 10 Dec 2024 14:08:23 +0900 Subject: [PATCH 12/37] =?UTF-8?q?[Feat]=20#223=20-=20DeleteDiaryAPI=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Global/Extensions/SwiftUI/View+.swift | 57 +++++++----- .../SwiftUI/FloatingButtonsSwiftUIView.swift | 92 ------------------- .../DetailDiary/DetailDiaryCoachedView.swift | 56 +++++++---- 3 files changed, 75 insertions(+), 130 deletions(-) delete mode 100644 Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift diff --git a/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift b/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift index 3d34934d..554a9bda 100644 --- a/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift +++ b/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift @@ -13,7 +13,7 @@ extension View { } var screenHeight: Double { - return screenSize.height + return screenSize.height } var screenWidth: Double { @@ -29,24 +29,39 @@ extension View { } func pushToUIKitView(_ viewController: UIViewController, dismissFullScreenCover: Bool = true) { - // 현재 presenting된 view controller - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootViewController = windowScene.windows.first?.rootViewController { - - // 현재 최상위 view controller (fullScreenCover 아래의 view controller) - var topViewController = rootViewController - while let presentedViewController = topViewController.presentedViewController { - topViewController = presentedViewController - } - - if let navigationController = topViewController as? UINavigationController { - navigationController.pushViewController(viewController, animated: true) - - if dismissFullScreenCover, - let presentingView = topViewController.presentingViewController { - presentingView.dismiss(animated: false, completion: nil) - } - } - } - } + // 현재 presenting된 view controller + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let rootViewController = windowScene.windows.first?.rootViewController { + + // 현재 최상위 view controller (fullScreenCover 아래의 view controller) + var topViewController = rootViewController + while let presentedViewController = topViewController.presentedViewController { + topViewController = presentedViewController + } + + if let navigationController = topViewController as? UINavigationController { + navigationController.pushViewController(viewController, animated: true) + + if dismissFullScreenCover, + let presentingView = topViewController.presentingViewController { + presentingView.dismiss(animated: false, completion: nil) + } + } + } + } + + func changeRootViewControllerAndPresent(_ viewControllerToPresent: UIViewController) { + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let window = windowScene.windows.first { + + window.rootViewController = viewControllerToPresent + + UIView.transition(with: window, + duration: 0.5, + options: .transitionCrossDissolve, + animations: nil) + + window.makeKeyAndVisible() + } + } } diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift deleted file mode 100644 index f064a577..00000000 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/FloatingButtonsSwiftUIView.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -// FloatingButtonsSwiftUIView.swift -// Smeem-iOS -// -// Created by Joon Baek on 11/26/24. -// - -import Combine -import SwiftUI - -final class FloatingButtonsViewModel: ObservableObject { - private(set) var editButtonTapped = PassthroughSubject() - private(set) var deleteButtonTapped = PassthroughSubject() -} - -struct FloatingButtonsSwiftUIView: View { - @ObservedObject var viewModel: FloatingButtonsViewModel - - @Environment(\.dismiss) var dismiss - @State private var showAlert = false - - var body: some View { - ZStack { - Color.black.opacity(0.3) - .ignoresSafeArea() - .onTapGesture { - dismiss() - } - - VStack { - Spacer() - - VStack(spacing: 0) { - Button(action: { - showAlert = true - }) { - Text("수정하기") - .font(.headline) - .frame(maxWidth: .infinity) - .padding() - .foregroundColor(.blue) - } - .alert("수정시 모든 코칭 내용이 사라집니다. 그래도 수정하시겠습니까?", - isPresented: $showAlert) { - Button("취소") { - dismiss() - } - Button("확인") { - viewModel.editButtonTapped.send() - } - } - - Divider() - .frame(height: 1) - .background(Color.gray.opacity(0.5)) - - Button(action: { - viewModel.deleteButtonTapped.send() - }) { - Text("삭제하기") - .font(.headline) - .frame(maxWidth: .infinity) - .padding() - .foregroundColor(.red) - } - } - .background(Color.white) - .cornerRadius(14) - - Button(action: { - dismiss() - }) { - Text("취소") - .font(.headline) - .frame(maxWidth: .infinity) - .padding() - .background(.white) - .foregroundColor(.blue) - .cornerRadius(14) - } - .padding(.top, 10) - - Spacer().frame(height: 20) - } - .padding(.horizontal, 20) - } - } -} - -#Preview { - FloatingButtonsSwiftUIView(viewModel: FloatingButtonsViewModel()) -} diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index 091c8867..8f4429ea 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -42,15 +42,18 @@ struct DetailDiaryCoachedView: View { } .onReceive(navigationViewModel.rightButtonTapped) { isShowingFloatingButtons = true - print("눌림?") } .confirmationDialog("", isPresented: $isShowingFloatingButtons) { Button("수정하기", role: .none) { - showEditConfirmation() + if navigationbarType == .diaryDetails { + showEditConfirmation() + } else { + navigateToEditDiary() + } } Button("삭제하기", role: .destructive) { -// performDelete() + deleteDiaryWithAPI(diaryID: diaryID ?? 0) } Button("취소", role: .cancel) { @@ -89,25 +92,25 @@ struct DetailDiaryCoachedView: View { } .onAppear { Task { - await fetchCoachingData(diaryID: diaryID ?? 0) + await fetchCoachingData(diaryID: diaryID ?? 0) } } } private func showEditConfirmation() { - let alert = UIAlertController( - title: "수정 확인", - message: "수정시 모든 코칭 내용이 사라집니다. 그래도 수정하시겠습니까?", - preferredStyle: .alert - ) - - alert.addAction(UIAlertAction(title: "취소", style: .cancel)) - alert.addAction(UIAlertAction(title: "확인", style: .default) { _ in - navigateToEditDiary() - }) - - UIApplication.shared.windows.first?.rootViewController?.present(alert, animated: true) - } + let alert = UIAlertController( + title: "수정 확인", + message: "수정시 모든 코칭 내용이 사라집니다. 그래도 수정하시겠습니까?", + preferredStyle: .alert + ) + + alert.addAction(UIAlertAction(title: "취소", style: .cancel)) + alert.addAction(UIAlertAction(title: "확인", style: .default) { _ in + navigateToEditDiary() + }) + + UIApplication.shared.windows.first?.rootViewController?.present(alert, animated: true) + } private func navigateToEditDiary() { let editVC = EditDiaryViewController() @@ -140,6 +143,25 @@ struct DetailDiaryCoachedView: View { self.error = error as? SmeemError } } + + func deleteDiaryWithAPI(diaryID: Int) { + SmeemLoadingView.showLoading() + + detailDiaryService.deleteDiary(diaryID: diaryID) { result in + + switch result { + case .success(_): + let homeVC = HomeViewController() +// let rootVC = UINavigationController(rootViewController: homeVC) + self.changeRootViewControllerAndPresent(homeVC) + case .failure(let error): + //Toast message + break + } + + SmeemLoadingView.hideLoading() + } + } } @available(iOS 17, *) From d3600bd21cc7055c5bacacbc92d559fcf4d4414c Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Tue, 10 Dec 2024 18:42:34 +0900 Subject: [PATCH 13/37] =?UTF-8?q?[Chore]=20#233=20-=20CustomSegmentControl?= =?UTF-8?q?=20Style=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SwiftUI/CustomSegmentedControl.swift | 107 +++++++++++++++++- .../SwiftUI/ScrollableDiaryView.swift | 2 +- .../DetailDiary/DetailDiaryResponse.swift | 9 +- .../DetailDiary/DetailDiaryCoachedView.swift | 9 +- 4 files changed, 115 insertions(+), 12 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift index 9bee5159..a231392a 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift @@ -16,19 +16,28 @@ struct CustomSegmentedControl: View { ForEach(options.indices, id: \.self) { index in SegmentButton( title: options[index], - isSelected: selectedIndex == index, + isSelected: isCoachingOn(index), + isFirstButton: index == 0, + isLastButton: index == options.count - 1, action: { selectedIndex = index } ) } } .background(Color.gray.opacity(0.2)) - .cornerRadius(8) + .cornerRadius(6) + } + + private func isCoachingOn(_ index: Int) -> Bool { + // "코칭 ON"일 때만 selected 상태로 처리 + return options[index] == "코칭 ON" && selectedIndex == index } } struct SegmentButton: View { let title: String let isSelected: Bool + let isFirstButton: Bool + let isLastButton: Bool let action: () -> Void var body: some View { @@ -40,15 +49,31 @@ struct SegmentButton: View { .background(backgroundColor) .foregroundColor(foregroundColor) .font(Font(UIFont.c5)) + .overlay( + Group { + // 'isSelected'일 때만 'isFirstButton'에 오버레이 추가 + if isSelected && isFirstButton { + CustomStrokeShape(includeLeadingCorners: false) + .stroke(Color(UIColor.gray500), lineWidth: 1) + } else if !isSelected { + // 'isSelected'가 아닐 때는 모든 버튼에 대해 모서리 처리 + CustomStrokeShape( + includeLeadingCorners: isFirstButton, + includeTrailingCorners: isLastButton + ) + .stroke(Color(UIColor.gray500), lineWidth: 1) + } + } + ) } } private var backgroundColor: Color { - isSelected ? (isCoachingOn ? Color(UIColor.point) : Color(UIColor.gray200)) : Color(UIColor.gray100) + isSelected ? Color(UIColor.point) : isFirstButton ? Color(UIColor.gray100) : Color(UIColor.white) } private var foregroundColor: Color { - isSelected ? .white : Color(UIColor.gray500) + isSelected ? Color(UIColor.smeemWhite) : Color(UIColor.gray500) } private var isCoachingOn: Bool { @@ -56,13 +81,83 @@ struct SegmentButton: View { } } +struct CustomStrokeShape: Shape { + var radius: CGFloat = 6 + var includeLeadingCorners: Bool = true + var includeTrailingCorners: Bool = true + + func path(in rect: CGRect) -> Path { + var path = Path() + + // Move to the starting point (TopLeading) + path.move(to: CGPoint(x: rect.minX + (includeLeadingCorners ? radius : 0), y: rect.minY)) + + // TopLeading Corner + if includeLeadingCorners { + path.addArc( + center: CGPoint(x: rect.minX + radius, y: rect.minY + radius), + radius: radius, + startAngle: .degrees(-90), + endAngle: .degrees(180), + clockwise: true + ) + } else { + path.addLine(to: CGPoint(x: rect.minX, y: rect.minY)) + } + + // BottomLeading Corner + path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY - (includeLeadingCorners ? radius : 0))) + if includeLeadingCorners { + path.addArc( + center: CGPoint(x: rect.minX + radius, y: rect.maxY - radius), + radius: radius, + startAngle: .degrees(180), + endAngle: .degrees(90), + clockwise: true + ) + } else { + path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY)) + } + + // BottomTrailing Corner + path.addLine(to: CGPoint(x: rect.maxX - (includeTrailingCorners ? radius : 0), y: rect.maxY)) + if includeTrailingCorners { + path.addArc( + center: CGPoint(x: rect.maxX - radius, y: rect.maxY - radius), + radius: radius, + startAngle: .degrees(90), + endAngle: .degrees(0), + clockwise: true + ) + } else { + path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY)) + } + + // TopTrailing Corner + path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY + (includeTrailingCorners ? radius : 0))) + if includeTrailingCorners { + path.addArc( + center: CGPoint(x: rect.maxX - radius, y: rect.minY + radius), + radius: radius, + startAngle: .degrees(0), + endAngle: .degrees(-90), + clockwise: true + ) + } else { + path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY)) + } + + path.closeSubpath() + return path + } +} + @available(iOS 17.0, *) #Preview { - @State var selectedIndex = 0 + @State var selectedIndex = 1 let options = ["코칭 OFF", "코칭 ON"] CustomSegmentedControl(selectedIndex: $selectedIndex, options: options) .frame(height: 32.scaledByHeight()) .padding(117.scaledByWidth()) } - diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/ScrollableDiaryView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/ScrollableDiaryView.swift index ee90bbda..fa3ca016 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/ScrollableDiaryView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/ScrollableDiaryView.swift @@ -31,7 +31,7 @@ struct ScrollableDiaryView: View { )) .padding(.horizontal, 18.scaledByHeight()) .padding(.bottom, 16.scaledByHeight()) - .foregroundColor(Color(UIColor.gray400)) + .foregroundColor(selectedIndex == 0 ? Color(UIColor.smeemBlack) : Color(UIColor.gray400)) .background( // 콘텐츠 크기를 측정하기 위한 백그라운드 GeometryReader { geometry in Color.clear diff --git a/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift b/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift index 5d346e62..7f40fee2 100644 --- a/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift +++ b/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift @@ -28,7 +28,14 @@ struct DetailDiaryResponse: Codable, Equatable { //} extension DetailDiaryResponse { - static let empty = DetailDiaryResponse(diaryId: 0, topic: "", content: "테스트임?", createdAt: "그래", username: "그래", isUpdated: true, corrections: [], correctionCount: 0, correctionMaxCount: 0) + static let empty = DetailDiaryResponse(diaryId: 0, topic: "", content: "테스트임?", createdAt: "그래", username: "그래", isUpdated: true, corrections: [CoachingResponse(original_sentence: "I have went to the park yesterdayI have went to the park yesterdayI have went to the park yesterdayI have went to the park yesterday", + corrected_sentence: "I went to the park yesterdayI went to the park yesterdayI went to the park yesterdayI went to the park yesterdayI went to the park yesterday", + reason: "현재완료 시제인 have went는 과거 시제인 went로 바꾸는 것이 맞습니다. yesterday와 함께 사용할 때는 단순 과거 시제를 사용해야 합니다.", + is_corrected: true), + CoachingResponse(original_sentence: "I have went to the park yesterdayI have went to the park yesterdayI have went럼뉴름ㄴ람ㄴㄹ 마넝롬나ㅣㅓㅇㄹ ㅗㅁ나ㅓㅇ롬나어롬나어롬나러ㅗㅁ나러 ㅗㄴ마러ㅗㅁ너ㅏ롬 ㄴ라ㅓ ㅗㄴㅁ라 왜 갑자 I have went to the park yesterdayI have went to the park yesterdayI have went to the park yesterdayI have went to the park yesterdayI have went to the park yesterday", + corrected_sentence: "I went to the park yesterdayI went to the park yesterdayI went to the park yesterday", + reason: "이러 이러한 이유로 이건 맞습니다", + is_corrected: true)], correctionCount: 0, correctionMaxCount: 0) } //struct CoachingResponse: Codable, Equatable { diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index 8f4429ea..55f24fde 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -14,8 +14,10 @@ struct DetailDiaryCoachedView: View { @StateObject private var navigationViewModel = NavigationViewModel() @State private var cancelBag = Set() - @State private var coachingsResponse = CoachingsResponse(corrections: []) - @State private var response: DetailDiaryResponse? +// @State private var coachingsResponse = CoachingsResponse(corrections: []) + @State private var coachingsResponse = CoachingsResponse.sample +// @State private var response: DetailDiaryResponse? + @State private var response:DetailDiaryResponse? = DetailDiaryResponse.empty @State private var isLoading = false @State private var error: SmeemError? @@ -92,7 +94,7 @@ struct DetailDiaryCoachedView: View { } .onAppear { Task { - await fetchCoachingData(diaryID: diaryID ?? 0) +// await fetchCoachingData(diaryID: diaryID ?? 0) } } } @@ -152,7 +154,6 @@ struct DetailDiaryCoachedView: View { switch result { case .success(_): let homeVC = HomeViewController() -// let rootVC = UINavigationController(rootViewController: homeVC) self.changeRootViewControllerAndPresent(homeVC) case .failure(let error): //Toast message From a2ec539a13008cb1b4565195a6e96a2c3884b4bb Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Tue, 10 Dec 2024 21:21:33 +0900 Subject: [PATCH 14/37] =?UTF-8?q?[CHORE]=20#235=20-=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=EB=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj | 6 ------ .../{ => Coaching}/Components/CoachingCompleteView.swift | 0 .../{ => Coaching}/Components/DiaryDetailView.swift | 0 .../Presentation/{ => Coaching}/Store/CoachingStore.swift | 0 4 files changed, 6 deletions(-) rename Smeem-iOS/Smeem-iOS/Presentation/{ => Coaching}/Components/CoachingCompleteView.swift (100%) rename Smeem-iOS/Smeem-iOS/Presentation/{ => Coaching}/Components/DiaryDetailView.swift (100%) rename Smeem-iOS/Smeem-iOS/Presentation/{ => Coaching}/Store/CoachingStore.swift (100%) diff --git a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj index 0169dc70..b503e31a 100644 --- a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj +++ b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj @@ -450,8 +450,6 @@ 377B3BF12CF618B90086E0BC /* SwiftUI */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = SwiftUI; sourceTree = ""; }; 4A17370E2D05C02E00B772C3 /* Toast */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Toast; sourceTree = ""; }; 4A17370F2D05C03600B772C3 /* LoadingView */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = LoadingView; sourceTree = ""; }; - 4A1737152D05C06E00B772C3 /* Components */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Components; sourceTree = ""; }; - 4A1737192D05C07100B772C3 /* Store */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Store; sourceTree = ""; }; 4AB3494E2CF22A070047C484 /* Global */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Global; sourceTree = ""; }; 4AB3494F2CF22A250047C484 /* Button */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Button; sourceTree = ""; }; 4AB349502CF22A2E0047C484 /* TextView */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = TextView; sourceTree = ""; }; @@ -615,8 +613,6 @@ isa = PBXGroup; children = ( 4AF050D82CEA01EA0055BC3F /* Coaching */, - 4A1737192D05C07100B772C3 /* Store */, - 4A1737152D05C06E00B772C3 /* Components */, 4AC047232A8FCA9700EBDC0E /* AuthManagement */, 4AA6FEE72C3ABD7C00E588E9 /* ResignSummray */, 4AA5E4B52BF24CEB00F308C8 /* BadgeBottomSheet */, @@ -1744,8 +1740,6 @@ 377B3BF12CF618B90086E0BC /* SwiftUI */, 4A17370E2D05C02E00B772C3 /* Toast */, 4A17370F2D05C03600B772C3 /* LoadingView */, - 4A1737152D05C06E00B772C3 /* Components */, - 4A1737192D05C07100B772C3 /* Store */, 4AB3494E2CF22A070047C484 /* Global */, 4AB3494F2CF22A250047C484 /* Button */, 4AB349502CF22A2E0047C484 /* TextView */, diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Components/CoachingCompleteView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift similarity index 100% rename from Smeem-iOS/Smeem-iOS/Presentation/Components/CoachingCompleteView.swift rename to Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Components/DiaryDetailView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/DiaryDetailView.swift similarity index 100% rename from Smeem-iOS/Smeem-iOS/Presentation/Components/DiaryDetailView.swift rename to Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/DiaryDetailView.swift diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Store/CoachingStore.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift similarity index 100% rename from Smeem-iOS/Smeem-iOS/Presentation/Store/CoachingStore.swift rename to Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift From c75f54c0d256923e571868313fb172f5a371273f Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Tue, 10 Dec 2024 21:54:26 +0900 Subject: [PATCH 15/37] =?UTF-8?q?[CHORE]=20#235=20-=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=ED=8F=B0?= =?UTF-8?q?=ED=8A=B8=20weight=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Coaching/Components/CoachingCompleteView.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift index 38e3bca9..291a820c 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift @@ -21,7 +21,7 @@ struct CoachingCompleteView: View { VStack(spacing: 16) { HStack { Text(coachingAppData.correctResultText) - .font(Font.custom("Pretendard", size: 16)) + .font(Font.custom("Pretendard", size: 16)).fontWeight(.regular) .foregroundColor(Color(UIColor.black)) .lineSpacing(0.375) Spacer() @@ -45,7 +45,6 @@ struct CoachingCompleteView: View { Spacer() } - .padding(.top) .padding(.horizontal, screenWidth * 0.048) VStack(spacing: 20) { From bc7b64e279161d41f9e2ebed0f0f677a4f230282 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Tue, 10 Dec 2024 22:13:30 +0900 Subject: [PATCH 16/37] =?UTF-8?q?[Fix]=20#233=20-=20EditViewController=20?= =?UTF-8?q?=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4=EC=85=98=20=EC=9D=B4?= =?UTF-8?q?=EC=8A=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/DetailDiary/DetailDiaryCoachedView.swift | 2 -- .../Diaries/View/Controllers/EditDiaryViewController.swift | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index 0dc629f9..187e039a 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -15,9 +15,7 @@ struct DetailDiaryCoachedView: View { @State private var cancelBag = Set() @State private var coachingsResponse = CoachingsResponse(corrections: []) -// @State private var coachingsResponse = CoachingsResponse.sample @State private var response: DetailDiaryResponse? -// @State private var response:DetailDiaryResponse? = DetailDiaryResponse.empty @State private var isLoading = false @State private var error: SmeemError? diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift b/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift index 9d82cfd2..c08adbab 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift @@ -169,7 +169,7 @@ extension EditDiaryViewController { func patchDiaryAPI() { PostDiaryAPI.shared.patchDiary(param: PatchDiaryRequest(content: diaryTextView.text), diaryID: diaryID) { response in DispatchQueue.main.async { - self.navigationController?.popViewController(animated: true) + self.changeRootViewControllerAndPresent(HomeViewController()) } } } From e9c77c3e2f1f598ec56e239f3b9c486306e2295e Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Tue, 10 Dec 2024 22:13:35 +0900 Subject: [PATCH 17/37] =?UTF-8?q?[CHORE]=20#235=20-=20=EC=99=84=EB=B2=BD?= =?UTF-8?q?=ED=95=9C=20=EB=AC=B8=EC=9E=A5=20filter=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Coaching/Store/CoachingStore.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift index 4e9966d4..e8bace4a 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift @@ -61,7 +61,7 @@ final class CoachingStore: Store, ObservableObject { do { state.hiddenIndex += 1 let coachingResponse = try await service.coachingPostAPI(diaryID: ID) - state.coachingAppData = CoachingAppData(corrections: coachingResponse.corrections, + state.coachingAppData = CoachingAppData(corrections: filiterCorrection(coachingResponse.corrections), correctResultText: correctTextResult(coachingResponse.corrections.count)) state.hiddenIndex += 1 } catch let error { @@ -73,6 +73,10 @@ final class CoachingStore: Store, ObservableObject { } } + func filiterCorrection(_ response: [CoachingResponse]) -> [CoachingResponse] { + return response.filter { $0.isCorrected } + } + func correctTextResult(_ count: Int) -> String { switch count { case 0: From f3f9a74d0c0d8ec1460e0fbd40c1bfb9a7ed589c Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Tue, 10 Dec 2024 22:59:19 +0900 Subject: [PATCH 18/37] =?UTF-8?q?[FEAT]=20#235=20-=20=EC=B2=A8=EC=82=AD=20?= =?UTF-8?q?=EC=9D=BC=EA=B8=B0=2010=EA=B0=9C=20=EC=A0=9C=ED=95=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Coaching/Store/CoachingStore.swift | 2 +- .../Coaching/Store/CoachingStoreTest.swift | 70 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift index e8bace4a..8efbb008 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift @@ -74,7 +74,7 @@ final class CoachingStore: Store, ObservableObject { } func filiterCorrection(_ response: [CoachingResponse]) -> [CoachingResponse] { - return response.filter { $0.isCorrected } + return response.filter { $0.isCorrected }.prefix(10).map{$0} } func correctTextResult(_ count: Int) -> String { diff --git a/Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift b/Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift new file mode 100644 index 00000000..aec0166c --- /dev/null +++ b/Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift @@ -0,0 +1,70 @@ +// +// CoachingStore.swift +// Smeem-iOSTests +// +// Created by 황찬미 on 12/10/24. +// + +import XCTest + +@testable import Smeem_iOS + +final class CoachingStoreTest: XCTestCase { + + var sut: CoachingStore! + var service: CoachingServiceProtocol! + + override func setUpWithError() throws { + service = CoachingService() + sut = CoachingStore(service: service, + diaryResponse: PostDiaryResponse.empty) + } + + override func tearDownWithError() throws { + sut = nil + } + + func test_첨삭데이터15개일때_10개로잘필터하는지() { + // Given + var filterResult = [CoachingResponse]() + for _ in 1...15 { + filterResult.append(CoachingResponse(originalSentence: "", + correctedSentence: "", + reason: "", + isCorrected: true)) + } + + var expectedResult = [CoachingResponse]() + for _ in 1...10 { + expectedResult.append(CoachingResponse(originalSentence: "", + correctedSentence: "", + reason: "", + isCorrected: true)) + } + + // When + let outputResult = sut.filiterCorrection(filterResult) + + // Then + XCTAssertEqual(outputResult, expectedResult) + } + + func test_첨삭데이터0개일때_0개로잘필터하는지() { + // Given + var filterResult = [CoachingResponse]() + for _ in 1...15 { + filterResult.append(CoachingResponse(originalSentence: "", + correctedSentence: "", + reason: "", + isCorrected: false)) + } + + var expectedResult = [CoachingResponse]() + + // When + let outputResult = sut.filiterCorrection(filterResult) + + // Then + XCTAssertEqual(outputResult, expectedResult) + } +} From b0f6c0226864fe7eedc411d8edda4ad5abdab788 Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Tue, 10 Dec 2024 23:26:16 +0900 Subject: [PATCH 19/37] =?UTF-8?q?[FEAT]=20#235=20-=20=EC=9B=90=EB=AC=B8=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=A5=20=EC=A1=B0=ED=95=A9=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/CoachingCompleteView.swift | 19 ++++++++++--------- .../Coaching/Store/CoachingStore.swift | 11 +++++++++-- .../Coaching/View/CoachingView.swift | 3 +-- .../Coaching/Store/CoachingStoreTest.swift | 19 +++++++++++++++++++ 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift index 291a820c..77b9d86b 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift @@ -9,7 +9,6 @@ import SwiftUI struct CoachingCompleteView: View { - @Binding var diaryText: String @Binding var coachingAppData: CoachingAppData @State var currentIndex = 0 @@ -28,9 +27,9 @@ struct CoachingCompleteView: View { } HStack { - Text(diaryText) + Text(coachingAppData.diaryText) .modifier(HighlightModifier( - diaryText: diaryText, + diaryText: coachingAppData.diaryText, corrections: coachingAppData.corrections, highlightIndex: currentIndex )) @@ -90,9 +89,11 @@ struct PageControl: View { } } -#Preview { - @State var diaryText = "I watched Avatar with my boyfriend at Hongdae CGV. I should have skimmed the previous season 
what they were saying and the universe(??). What I was annoyed then was 두팔 didn’t know that as me. I think 두팔 who is my boyfriend should study before wathcing…. but Avatar2 is amazing movie I think. In my personal opinion, the jjin main character " - @State var coachingResponse = CoachingAppData(corrections: CoachingsResponse.sample.corrections, correctResultText: "테스트") - - CoachingCompleteView(diaryText: $diaryText, coachingAppData: $coachingResponse) -} +//#Preview { +// @State var diaryText = "I watched Avatar with my boyfriend at Hongdae CGV. I should have skimmed the previous season 
what they were saying and the universe(??). What I was annoyed then was 두팔 didn’t know that as me. I think 두팔 who is my boyfriend should study before wathcing…. but Avatar2 is amazing movie I think. In my personal opinion, the jjin main character " +// @State var coachingResponse = CoachingAppData(diaryText: "", +// corrections: CoachingsResponse.sample.corrections, +// correctResultText: "테스트") +// +// CoachingCompleteView(coachingAppData: coachingResponse, currentIndex: 0) +//} diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift index 8efbb008..6ba652f1 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift @@ -8,6 +8,7 @@ import Foundation struct CoachingAppData { + var diaryText: String var corrections: [CoachingResponse] var correctResultText: String } @@ -30,7 +31,8 @@ final class CoachingStore: Store, ObservableObject { struct State { var detailDiaryResponse = DetailDiaryResponse.empty - var coachingAppData = CoachingAppData(corrections: CoachingsResponse.sample.corrections, + var coachingAppData = CoachingAppData(diaryText: "", + corrections: CoachingsResponse.sample.corrections, correctResultText: "첨삭 중이에요") var toastErrorMessage: SmeemError? = nil var toastMessage: SmeemToast? = .completed @@ -61,7 +63,8 @@ final class CoachingStore: Store, ObservableObject { do { state.hiddenIndex += 1 let coachingResponse = try await service.coachingPostAPI(diaryID: ID) - state.coachingAppData = CoachingAppData(corrections: filiterCorrection(coachingResponse.corrections), + state.coachingAppData = CoachingAppData(diaryText: combineCorrectionText(coachingResponse.corrections), + corrections: filiterCorrection(coachingResponse.corrections), correctResultText: correctTextResult(coachingResponse.corrections.count)) state.hiddenIndex += 1 } catch let error { @@ -73,6 +76,10 @@ final class CoachingStore: Store, ObservableObject { } } + func combineCorrectionText(_ response: [CoachingResponse]) -> String { + return response.map{ $0.originalSentence }.joined(separator: " ") + } + func filiterCorrection(_ response: [CoachingResponse]) -> [CoachingResponse] { return response.filter { $0.isCorrected }.prefix(10).map{$0} } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/View/CoachingView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/View/CoachingView.swift index 28d4c25b..1d330497 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/View/CoachingView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/View/CoachingView.swift @@ -86,8 +86,7 @@ struct CoachingView: View { // MARK: 첨삭 화면 } else { - CoachingCompleteView(diaryText: $store.state.detailDiaryResponse.content, - coachingAppData: $store.state.coachingAppData) + CoachingCompleteView(coachingAppData: $store.state.coachingAppData) } // MARK: 첫 진입시 토스트뷰 실행 diff --git a/Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift b/Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift index aec0166c..f03c754c 100644 --- a/Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift +++ b/Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift @@ -67,4 +67,23 @@ final class CoachingStoreTest: XCTestCase { // Then XCTAssertEqual(outputResult, expectedResult) } + + func test_원문일기_잘조합해주는지() { + // Given + var filterResult = [CoachingResponse]() + for i in 1...3 { + filterResult.append(CoachingResponse(originalSentence: "안녕", + correctedSentence: "", + reason: "", + isCorrected: false)) + } + + var expectedResult = "안녕 안녕 안녕" + + // When + let outputResult = sut.combineCorrectionText(filterResult) + + // Then + XCTAssertEqual(outputResult, expectedResult) + } } From ea8de32e595056ab23fc6e382653a9639a5f0bf5 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Tue, 10 Dec 2024 23:43:56 +0900 Subject: [PATCH 20/37] =?UTF-8?q?[Feat]=20#233=20-=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DetailDiary/DetailDiaryCoachedView.swift | 22 ++++++++++++++++--- .../Home/HomeViewController.swift | 6 +---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index 187e039a..e02d1967 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -17,6 +17,7 @@ struct DetailDiaryCoachedView: View { @State private var coachingsResponse = CoachingsResponse(corrections: []) @State private var response: DetailDiaryResponse? @State private var isLoading = false + @State private var onError = false @State private var error: SmeemError? @Binding var diaryID: Int? @@ -27,6 +28,8 @@ struct DetailDiaryCoachedView: View { @State private var selectedIndex = 0 @State private var navigationbarType: NavigationbarType = .diaryDetails + @State private var toastErrorMessage: SmeemError? = nil + var toastMessage: SmeemToast? = .completed @Environment(\.dismiss) private var dismiss private let detailDiaryService = DetailDiaryService.shared @@ -95,6 +98,19 @@ struct DetailDiaryCoachedView: View { await fetchCoachingData(diaryID: diaryID ?? 0) } } + .overlay { + if isLoading { + SmemeEmptyView() + SmemeLoadingView() + } + + if onError { + SmeemErrorToastView(type: $toastErrorMessage) + .onDisappear { + onError = false + } + } + } } private func showEditConfirmation() { @@ -141,6 +157,7 @@ struct DetailDiaryCoachedView: View { } catch { isLoading = false self.error = error as? SmeemError + self.onError = true } } @@ -154,10 +171,9 @@ struct DetailDiaryCoachedView: View { let homeVC = HomeViewController() self.changeRootViewControllerAndPresent(homeVC) case .failure(let error): - //Toast message - break + toastErrorMessage = error + break } - SmeemLoadingView.hideLoading() } } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Home/HomeViewController.swift b/Smeem-iOS/Smeem-iOS/Presentation/Home/HomeViewController.swift index ad0ae64e..e0eb102b 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Home/HomeViewController.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Home/HomeViewController.swift @@ -253,11 +253,7 @@ final class HomeViewController: BaseViewController { } } - @objc func fullViewButtonDidTap(_ gesture: UITapGestureRecognizer) { -// let detailDiaryVC = DetailDiaryViewController() -// detailDiaryVC.diaryId = homeDiaryDict[currentDate.toString("yyyy-MM-dd")]?.diaryId ?? 0 -// self.navigationController?.pushViewController(detailDiaryVC, animated: true) - + @objc func fullViewButtonDidTap(_ gesture: UITapGestureRecognizer) { let diaryID = homeDiaryDict[currentDate.toString("yyyy-MM-dd")]?.diaryId ?? 0 @State var defaultIndex = 0 From 2369602d967dafce152374848350864498742933 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Wed, 11 Dec 2024 00:04:59 +0900 Subject: [PATCH 21/37] =?UTF-8?q?[Chore]=20#233=20-=20=ED=8C=9D=EC=97=85?= =?UTF-8?q?=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=9D=B5=EC=8A=A4=ED=85=90?= =?UTF-8?q?=EC=85=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Global/Extensions/SwiftUI/View+.swift | 27 ++++++++++++++++++ .../DetailDiary/DetailDiaryCoachedView.swift | 28 ++++++++----------- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift b/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift index 554a9bda..4af09b2c 100644 --- a/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift +++ b/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift @@ -20,6 +20,33 @@ extension View { return screenSize.width } + func showEditConfirmation( + title: String, + message: String, + firstActionTitle: String, + secondActionTitle: String, + firstActionHandler: (() -> Void)? = nil, + secondActionHandler: (() -> Void)? = nil + ) { + let alert = UIAlertController( + title: title, + message: message, + preferredStyle: .alert + ) + + alert.addAction(UIAlertAction(title: firstActionTitle, style: .cancel) { _ in + firstActionHandler?() + }) + + alert.addAction(UIAlertAction(title: secondActionTitle, style: .default) { _ in + secondActionHandler?() + }) + + if let topViewController = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.rootViewController { + topViewController.present(alert, animated: true) + } + } + func changeRootViewController(_ viewController: UIViewController) { guard let window = UIApplication.shared.windows.first else { return } UIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve, animations: { diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index e02d1967..f84276ea 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -49,7 +49,18 @@ struct DetailDiaryCoachedView: View { .confirmationDialog("", isPresented: $isShowingFloatingButtons) { Button("수정하기", role: .none) { if navigationbarType == .diaryDetails { - showEditConfirmation() + showEditConfirmation( + title: "수정 확인", + message: "수정시 모든 코칭 내용이 사라집니다. 그래도 수정하시겠습니까?", + firstActionTitle: "취소", + secondActionTitle: "확인", + firstActionHandler: { + dismiss() + }, + secondActionHandler: { + navigateToEditDiary() + } + ) } else { navigateToEditDiary() } @@ -113,21 +124,6 @@ struct DetailDiaryCoachedView: View { } } - private func showEditConfirmation() { - let alert = UIAlertController( - title: "수정 확인", - message: "수정시 모든 코칭 내용이 사라집니다. 그래도 수정하시겠습니까?", - preferredStyle: .alert - ) - - alert.addAction(UIAlertAction(title: "취소", style: .cancel)) - alert.addAction(UIAlertAction(title: "확인", style: .default) { _ in - navigateToEditDiary() - }) - - UIApplication.shared.windows.first?.rootViewController?.present(alert, animated: true) - } - private func navigateToEditDiary() { let editVC = EditDiaryViewController() editVC.diaryID = self.diaryID ?? 0 From 6f48b4efc704b1d10093bed68ed8f07b5637538e Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Wed, 11 Dec 2024 00:05:43 +0900 Subject: [PATCH 22/37] [FEAT] #239 - diary detail amplitude --- .../Global/Constants/AmplitudeConstant.swift | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/Constants/AmplitudeConstant.swift b/Smeem-iOS/Smeem-iOS/Global/Constants/AmplitudeConstant.swift index 2ba50fb8..e7fb3f56 100644 --- a/Smeem-iOS/Smeem-iOS/Global/Constants/AmplitudeConstant.swift +++ b/Smeem-iOS/Smeem-iOS/Global/Constants/AmplitudeConstant.swift @@ -131,15 +131,24 @@ enum AmplitudeConstant { } enum diaryDetail { + case toggle_click(String) case mydiary_click - case mydiary_edit + case mydiary_view(Bool) + case mydiary_edit(Bool) + case mydiary_edit_complete_click(Bool) var event: BaseEvent { switch self { + case .toggle_click(let toggle): + return BaseEvent(eventType: "toggle_click", eventProperties: ["toggle": toggle]) case .mydiary_click: return BaseEvent(eventType: "mydiary_click", eventProperties: nil) - case .mydiary_edit: - return BaseEvent(eventType: "mydiary_edit", eventProperties: nil) + case .mydiary_view(let hasCoaching): + return BaseEvent(eventType: "mydiary_view", eventProperties: ["has_coaching": hasCoaching]) + case .mydiary_edit(let hasCoaching): + return BaseEvent(eventType: "mydiary_edit", eventProperties: ["has_coaching": hasCoaching]) + case .mydiary_edit_complete_click(let hasCoaching): + return BaseEvent(eventType: "mydiary_edit_complete_click", eventProperties: ["has_coaching": hasCoaching]) } } } @@ -175,4 +184,22 @@ enum AmplitudeConstant { } } } + + enum coaching { + case coaching_try_click + case coaching_exit_click + case coaching_load_view + case coaching_result_view + case coaching_feedback_view + + var event: BaseEvent { + switch self { + case .achievement_view: + return BaseEvent(eventType: "achievement_view", eventProperties: nil) + case .badge_bottom_sheet_view(let type, let hasBadge): + return BaseEvent(eventType: "badge_bottom_sheet_view", eventProperties: ["BadgeType":type, + "hasBadge":hasBadge]) + } + } + } } From f60fc1554a3b3cfc3f1299456efc4e14c3c059ef Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Wed, 11 Dec 2024 00:14:32 +0900 Subject: [PATCH 23/37] =?UTF-8?q?[Fix]=20#233=20-=20=ED=86=A0=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EC=9D=B4=EC=8A=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DetailDiary/DetailDiaryCoachedView.swift | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index f84276ea..3272878d 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -87,8 +87,6 @@ struct DetailDiaryCoachedView: View { } else { if isLoading { ProgressView("Loading...") - } else if let error = error { - Text("Error: \(error.localizedDescription)") } } @@ -116,10 +114,17 @@ struct DetailDiaryCoachedView: View { } if onError { - SmeemErrorToastView(type: $toastErrorMessage) - .onDisappear { - onError = false + ZStack { + Color.clear + VStack { + Spacer() + SmeemErrorToastView(type: $toastErrorMessage) + .padding(.bottom, 20.scaledByHeight()) } + } + .onDisappear { + onError = false + } } } } From 73cc9338cbd361b6139c440b2823022a54d33a23 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Wed, 11 Dec 2024 00:25:16 +0900 Subject: [PATCH 24/37] =?UTF-8?q?[Add]=20#239=20-=20Double+=20=EB=88=84?= =?UTF-8?q?=EB=9D=BD=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj | 64 ++++++------------- 1 file changed, 19 insertions(+), 45 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj index 0c7a2012..4c28789a 100644 --- a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj +++ b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj @@ -17,7 +17,6 @@ 370BD0B32CFB65BE009560DB /* RandomTopicView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370BD0AA2CFB65BE009560DB /* RandomTopicView.swift */; }; 370BD0B42CFB65BE009560DB /* AlarmCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370BD0A32CFB65BE009560DB /* AlarmCollectionViewCell.swift */; }; 370BD0B52CFB65BE009560DB /* AlarmDefaultModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370BD0A42CFB65BE009560DB /* AlarmDefaultModel.swift */; }; - 370BD0B82CFBF50C009560DB /* Double+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370BD0B72CFBF50C009560DB /* Double+.swift */; }; 371107DA2AC99099007A4AC2 /* KeyboardFollowingLayoutHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371107D92AC99099007A4AC2 /* KeyboardFollowingLayoutHandler.swift */; }; 371107DD2ACAB571007A4AC2 /* BaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371107DC2ACAB571007A4AC2 /* BaseView.swift */; }; 371107DF2ACAB709007A4AC2 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371107DE2ACAB709007A4AC2 /* BaseViewController.swift */; }; @@ -40,6 +39,8 @@ 375B628B2C590D0D00DA8E30 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 375B628A2C590D0D00DA8E30 /* FirebaseMessaging */; }; 375B628D2C590D0D00DA8E30 /* FirebaseRemoteConfig in Frameworks */ = {isa = PBXBuildFile; productRef = 375B628C2C590D0D00DA8E30 /* FirebaseRemoteConfig */; }; 3761116C2A278D0E0095EC5A /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761116B2A278D0E0095EC5A /* String+.swift */; }; + 376947892D0894A2006A46B1 /* Double+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376947882D0894A2006A46B1 /* Double+.swift */; }; + 377B3BF02CF613710086E0BC /* HighlightModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377B3BEF2CF613710086E0BC /* HighlightModifier.swift */; }; 3785072F2BD1480C004CC922 /* SharedDiaryDataService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37499E3C2BD0C3A100BA6FAF /* SharedDiaryDataService.swift */; }; 378B20EE2BA0A01600604935 /* ForeignDiaryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378B20ED2BA0A01600604935 /* ForeignDiaryViewModel.swift */; }; 378B20F02BA0A02400604935 /* StepOneKoreanDiaryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378B20EF2BA0A02400604935 /* StepOneKoreanDiaryViewModel.swift */; }; @@ -67,10 +68,6 @@ 37B123B62CEEE58E00ED973A /* DetailDiaryCoachedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B123B52CEEE58E00ED973A /* DetailDiaryCoachedView.swift */; }; 37BCADF22BC3FFBF006EF960 /* DetailDiaryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BCADF12BC3FFBF006EF960 /* DetailDiaryViewModel.swift */; }; 37BDC9872C4FEA940075F68A /* SendFeedbackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BDC9862C4FEA940075F68A /* SendFeedbackView.swift */; }; - 37BF485B2D08676A0013669A /* HighlightModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BF485A2D08676A0013669A /* HighlightModifier.swift */; }; - 37BF485E2D0867DC0013669A /* CoachingResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BF485C2D0867DC0013669A /* CoachingResponse.swift */; }; - 37BF48742D086A6C0013669A /* SmemeLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BF48722D086A6C0013669A /* SmemeLoadingView.swift */; }; - 37BF48772D086A8B0013669A /* SmemeToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BF48752D086A8B0013669A /* SmemeToastView.swift */; }; 37DCA6572A47574300FF8F90 /* RandomTopicAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DCA6562A47574300FF8F90 /* RandomTopicAPI.swift */; }; 37DCA65A2A47598700FF8F90 /* RandomTopicService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DCA6592A47598700FF8F90 /* RandomTopicService.swift */; }; 37DCA65D2A475B5100FF8F90 /* RandomTopicResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DCA65C2A475B5100FF8F90 /* RandomTopicResponse.swift */; }; @@ -248,7 +245,6 @@ 370BD0A92CFB65BE009560DB /* DiaryScrollerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryScrollerView.swift; sourceTree = ""; }; 370BD0AA2CFB65BE009560DB /* RandomTopicView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RandomTopicView.swift; sourceTree = ""; }; 370BD0AB2CFB65BE009560DB /* SeparationLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparationLine.swift; sourceTree = ""; }; - 370BD0B72CFBF50C009560DB /* Double+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+.swift"; sourceTree = ""; }; 371107D92AC99099007A4AC2 /* KeyboardFollowingLayoutHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardFollowingLayoutHandler.swift; sourceTree = ""; }; 371107DC2ACAB571007A4AC2 /* BaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseView.swift; sourceTree = ""; }; 371107DE2ACAB709007A4AC2 /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; @@ -268,6 +264,8 @@ 374F828B2AC327A200C128B9 /* SmeemTextViewHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmeemTextViewHandler.swift; sourceTree = ""; }; 374FAF802A2CACCF00237A1A /* DiaryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryViewController.swift; sourceTree = ""; }; 3761116B2A278D0E0095EC5A /* String+.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+.swift"; sourceTree = ""; }; + 376947882D0894A2006A46B1 /* Double+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+.swift"; sourceTree = ""; }; + 377B3BEF2CF613710086E0BC /* HighlightModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightModifier.swift; sourceTree = ""; }; 378B20ED2BA0A01600604935 /* ForeignDiaryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForeignDiaryViewModel.swift; sourceTree = ""; }; 378B20EF2BA0A02400604935 /* StepOneKoreanDiaryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepOneKoreanDiaryViewModel.swift; sourceTree = ""; }; 378B20F12BA0A03000604935 /* StepTwoKoreanDiaryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepTwoKoreanDiaryViewModel.swift; sourceTree = ""; }; @@ -294,10 +292,6 @@ 37B123B52CEEE58E00ED973A /* DetailDiaryCoachedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailDiaryCoachedView.swift; sourceTree = ""; }; 37BCADF12BC3FFBF006EF960 /* DetailDiaryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailDiaryViewModel.swift; sourceTree = ""; }; 37BDC9862C4FEA940075F68A /* SendFeedbackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendFeedbackView.swift; sourceTree = ""; }; - 37BF485A2D08676A0013669A /* HighlightModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightModifier.swift; sourceTree = ""; }; - 37BF485C2D0867DC0013669A /* CoachingResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoachingResponse.swift; sourceTree = ""; }; - 37BF48722D086A6C0013669A /* SmemeLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmemeLoadingView.swift; sourceTree = ""; }; - 37BF48752D086A8B0013669A /* SmemeToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmemeToastView.swift; sourceTree = ""; }; 37DCA6562A47574300FF8F90 /* RandomTopicAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RandomTopicAPI.swift; sourceTree = ""; }; 37DCA6592A47598700FF8F90 /* RandomTopicService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RandomTopicService.swift; sourceTree = ""; }; 37DCA65C2A475B5100FF8F90 /* RandomTopicResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RandomTopicResponse.swift; sourceTree = ""; }; @@ -465,6 +459,8 @@ 4AB349522CF22AD30047C484 /* Auth */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Auth; sourceTree = ""; }; 4AB349532CF22AD90047C484 /* Badge */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Badge; sourceTree = ""; }; 4AB349562CF22BFF0047C484 /* EditUser */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = EditUser; sourceTree = ""; }; + 4AB349BA2CF23B770047C484 /* Coaching */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Coaching; sourceTree = ""; }; + 4AB349BC2CF23D210047C484 /* Coaching */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Coaching; sourceTree = ""; }; 4AF050CE2CE9DE010055BC3F /* Coaching */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Coaching; sourceTree = ""; }; 4AF050D82CEA01EA0055BC3F /* Coaching */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Coaching; sourceTree = ""; }; /* End PBXFileSystemSynchronizedRootGroup section */ @@ -566,8 +562,8 @@ 373D29912CBFE16B00A559A3 /* SwiftUI */ = { isa = PBXGroup; children = ( + 377B3BEF2CF613710086E0BC /* HighlightModifier.swift */, 373D29922CBFE17B00A559A3 /* View+.swift */, - 37BF485A2D08676A0013669A /* HighlightModifier.swift */, ); path = SwiftUI; sourceTree = ""; @@ -657,7 +653,7 @@ 4A4FEB002B721956001BBDF3 /* Combine+.swift */, 4AB7C9182B75F9B500845733 /* GesturePublisher+.swift */, 4AF050EA2CEA300F0055BC3F /* MoyaProvier+.swift */, - 370BD0B72CFBF50C009560DB /* Double+.swift */, + 376947882D0894A2006A46B1 /* Double+.swift */, ); path = Extensions; sourceTree = ""; @@ -747,30 +743,6 @@ path = Controllers; sourceTree = ""; }; - 37BF485D2D0867DC0013669A /* Coaching */ = { - isa = PBXGroup; - children = ( - 37BF485C2D0867DC0013669A /* CoachingResponse.swift */, - ); - path = Coaching; - sourceTree = ""; - }; - 37BF48732D086A6C0013669A /* LoadingView */ = { - isa = PBXGroup; - children = ( - 37BF48722D086A6C0013669A /* SmemeLoadingView.swift */, - ); - path = LoadingView; - sourceTree = ""; - }; - 37BF48762D086A8B0013669A /* Toast */ = { - isa = PBXGroup; - children = ( - 37BF48752D086A8B0013669A /* SmemeToastView.swift */, - ); - path = Toast; - sourceTree = ""; - }; 37CD0DB32A1DEE64001F03E7 /* Diaries */ = { isa = PBXGroup; children = ( @@ -926,6 +898,7 @@ 4A07F8D92B821523004185F2 /* Smeem-iOSTests */ = { isa = PBXGroup; children = ( + 4AB349BC2CF23D210047C484 /* Coaching */, 4AF78D9C2B84AB5D0098E1FA /* Base */, 4A07F8E12B821529004185F2 /* Onboarding */, ); @@ -978,7 +951,7 @@ 4A0EA45C2A014126006CCE52 /* NetworkDataModel */ = { isa = PBXGroup; children = ( - 37BF485D2D0867DC0013669A /* Coaching */, + 4AB349BA2CF23B770047C484 /* Coaching */, 4AB349562CF22BFF0047C484 /* EditUser */, 4AB349532CF22AD90047C484 /* Badge */, 4AB349522CF22AD30047C484 /* Auth */, @@ -1032,9 +1005,9 @@ 4A1EE9552A4DFB86007BFEF3 /* SmeemComponent */ = { isa = PBXGroup; children = ( - 37BF48732D086A6C0013669A /* LoadingView */, + 4A17370F2D05C03600B772C3 /* LoadingView */, + 4A17370E2D05C02E00B772C3 /* Toast */, 4AB349502CF22A2E0047C484 /* TextView */, - 37BF48762D086A8B0013669A /* Toast */, 4AB3494F2CF22A250047C484 /* Button */, 4AB3494E2CF22A070047C484 /* Global */, 379789012AAB9B1900C61EF4 /* NavigationBar */, @@ -1746,6 +1719,9 @@ dependencies = ( 4A07F8DD2B821523004185F2 /* PBXTargetDependency */, ); + fileSystemSynchronizedGroups = ( + 4AB349BC2CF23D210047C484 /* Coaching */, + ); name = "Smeem-iOSTests"; productName = "Smeem-iOSTests"; productReference = 4A07F8D82B821523004185F2 /* Smeem-iOSTests.xctest */; @@ -1774,6 +1750,7 @@ 4AB349522CF22AD30047C484 /* Auth */, 4AB349532CF22AD90047C484 /* Badge */, 4AB349562CF22BFF0047C484 /* EditUser */, + 4AB349BA2CF23B770047C484 /* Coaching */, 4AF050CE2CE9DE010055BC3F /* Coaching */, 4AF050D82CEA01EA0055BC3F /* Coaching */, ); @@ -1907,6 +1884,7 @@ 4AC705AE2BECF0D4003C5310 /* EditPlanViewModel.swift in Sources */, 4AF7C22F2BFB797600E8C6CD /* LockBadgeCollectionViewCell.swift in Sources */, 6F294A3E2A26177B00856CC8 /* TrainingGoalViewController.swift in Sources */, + 376947892D0894A2006A46B1 /* Double+.swift in Sources */, 4ABCBCCE2BDE95D0003138A8 /* MyPlanResponse.swift in Sources */, 4A9731D92BAAB70500DEC0C8 /* UpdateResponse.swift in Sources */, 4ABCBCEC2BE261B0003138A8 /* TrainingCollectionViewDatasource.swift in Sources */, @@ -1930,7 +1908,6 @@ 370BD0B32CFB65BE009560DB /* RandomTopicView.swift in Sources */, 370BD0B42CFB65BE009560DB /* AlarmCollectionViewCell.swift in Sources */, 370BD0B52CFB65BE009560DB /* AlarmDefaultModel.swift in Sources */, - 37BF48742D086A6C0013669A /* SmemeLoadingView.swift in Sources */, 4AB7C9302B78B44500845733 /* LoginBottomSheetViewController.swift in Sources */, 4A08480E2B555FD0008327C7 /* AmplitudeConstant.swift in Sources */, 4A3774842A42E6EA00357DD1 /* ConfigConstant.swift in Sources */, @@ -1946,7 +1923,6 @@ 4A004D5B2B4EE29A003C8936 /* PushTestService.swift in Sources */, 379789052AAC706800C61EF4 /* SmeemNavigationFactory.swift in Sources */, 37DCA65D2A475B5100FF8F90 /* RandomTopicResponse.swift in Sources */, - 370BD0B82CFBF50C009560DB /* Double+.swift in Sources */, 4ABCBCCC2BDE8E44003138A8 /* MySummaryService.swift in Sources */, 371107DA2AC99099007A4AC2 /* KeyboardFollowingLayoutHandler.swift in Sources */, 37B123B62CEEE58E00ED973A /* DetailDiaryCoachedView.swift in Sources */, @@ -1954,10 +1930,10 @@ 4ABCBCE52BE25D82003138A8 /* TrainingPlanViewController.swift in Sources */, 4AB7C9192B75F9B500845733 /* GesturePublisher+.swift in Sources */, 37A574CC29FF990E00312453 /* UIViewController+.swift in Sources */, - 37BF485B2D08676A0013669A /* HighlightModifier.swift in Sources */, 4ABCBCEA2BE26079003138A8 /* TrainingPlanViewModel.swift in Sources */, 4A9E10E42A43468600295D07 /* BaseTargetType.swift in Sources */, 37A574C329FF6E9C00312453 /* Constant.swift in Sources */, + 377B3BF02CF613710086E0BC /* HighlightModifier.swift in Sources */, 4AC1D6832B4ED38200D39A98 /* OnboardingModel.swift in Sources */, 4AC705932BEA1E52003C5310 /* LanguageContainerView.swift in Sources */, 4A004D602B4EE2BD003C8936 /* MyPageAPI.swift in Sources */, @@ -2008,7 +1984,6 @@ 4ADA41772A556209001C0285 /* LoadingView.swift in Sources */, 4ADCA2D62A9272E9002904EB /* EditAlarmViewController.swift in Sources */, 4A004D592B4EE28D003C8936 /* PushTestAPI.swift in Sources */, - 37BF48772D086A8B0013669A /* SmemeToastView.swift in Sources */, 6F294A432A26179700856CC8 /* ServiceAcceptViewController.swift in Sources */, 4AD04B402A1921AE004B7A58 /* CorrectionViewController.swift in Sources */, 4A1882FA2A8BBD0D0088F590 /* SmeemStartViewController.swift in Sources */, @@ -2050,7 +2025,6 @@ 6F294A422A26178C00856CC8 /* UserNickNameViewController.swift in Sources */, 4AC047252A8FCAE100EBDC0E /* AuthManagementViewController.swift in Sources */, 374FAF812A2CACCF00237A1A /* DiaryViewController.swift in Sources */, - 37BF485E2D0867DC0013669A /* CoachingResponse.swift in Sources */, 37DCA65A2A47598700FF8F90 /* RandomTopicService.swift in Sources */, 4AB7C9262B78914100845733 /* SplashViewModel.swift in Sources */, 4AF7C2312BFB7A4F00E8C6CD /* MyPlanDeactiveCollectionViewCell.swift in Sources */, @@ -2287,7 +2261,7 @@ CODE_SIGN_ENTITLEMENTS = "Smeem-iOS/Smeem-iOS.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 20240811; + CURRENT_PROJECT_VERSION = 20241203; DEVELOPMENT_TEAM = K8LLWYQWXD; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "Smeem-iOS/Info.plist"; From 123dae5d9b66f7fbb2032a4de744dde8c8ccfc87 Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Wed, 11 Dec 2024 00:29:18 +0900 Subject: [PATCH 25/37] =?UTF-8?q?[FEAT]=20#239=20-=20coaching=20amplitude?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Global/Constants/AmplitudeConstant.swift | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/Constants/AmplitudeConstant.swift b/Smeem-iOS/Smeem-iOS/Global/Constants/AmplitudeConstant.swift index e7fb3f56..0f513981 100644 --- a/Smeem-iOS/Smeem-iOS/Global/Constants/AmplitudeConstant.swift +++ b/Smeem-iOS/Smeem-iOS/Global/Constants/AmplitudeConstant.swift @@ -186,19 +186,24 @@ enum AmplitudeConstant { } enum coaching { - case coaching_try_click - case coaching_exit_click + case coaching_try_click(Bool) + case coaching_exit_click(Bool) case coaching_load_view case coaching_result_view - case coaching_feedback_view + case coaching_feedback_view(Int) var event: BaseEvent { switch self { - case .achievement_view: - return BaseEvent(eventType: "achievement_view", eventProperties: nil) - case .badge_bottom_sheet_view(let type, let hasBadge): - return BaseEvent(eventType: "badge_bottom_sheet_view", eventProperties: ["BadgeType":type, - "hasBadge":hasBadge]) + case .coaching_try_click(let isActive): + return BaseEvent(eventType: "coaching_try_click", eventProperties: ["active": isActive]) + case .coaching_exit_click(let isActive): + return BaseEvent(eventType: "coaching_exit_click", eventProperties: ["active": isActive]) + case .coaching_load_view: + return BaseEvent(eventType: "coaching_load_view", eventProperties: nil) + case .coaching_result_view: + return BaseEvent(eventType: "coaching_result_view", eventProperties: nil) + case .coaching_feedback_view(let index): + return BaseEvent(eventType: "badge_bottom_sheet_view", eventProperties: ["Index": index]) } } } From ad2d86ba7f1428669d124271bfa5316b596e2426 Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Wed, 11 Dec 2024 01:01:55 +0900 Subject: [PATCH 26/37] =?UTF-8?q?[FEAT]=20#239=20-=20Coaching=20Amplitude?= =?UTF-8?q?=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/CoachingCompleteView.swift | 7 ++--- .../Coaching/Store/CoachingStore.swift | 29 +++++++++++++++++-- .../Coaching/View/CoachingView.swift | 12 ++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift index 77b9d86b..f44c2af3 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift @@ -10,7 +10,6 @@ import SwiftUI struct CoachingCompleteView: View { @Binding var coachingAppData: CoachingAppData - @State var currentIndex = 0 var body: some View { @@ -31,7 +30,7 @@ struct CoachingCompleteView: View { .modifier(HighlightModifier( diaryText: coachingAppData.diaryText, corrections: coachingAppData.corrections, - highlightIndex: currentIndex + highlightIndex: coachingAppData.currentIndex )) .font(Font.custom("Pretendard", size: 16)) .foregroundColor(Color(UIColor.gray400)) @@ -50,7 +49,7 @@ struct CoachingCompleteView: View { Rectangle() .frame(height: 8) .foregroundStyle(Color(UIColor.gray100)) - TabView(selection: $currentIndex) { + TabView(selection: $coachingAppData.currentIndex) { ForEach(coachingAppData.corrections.indices, id: \.self) { item in ScrollView { VStack(spacing: 8) { @@ -64,7 +63,7 @@ struct CoachingCompleteView: View { .frame(width: screenWidth, height: screenHeight * (326/screenHeight), alignment: .top) .tabViewStyle(.page(indexDisplayMode: .never)) - PageControl(currentPage: $currentIndex, + PageControl(currentPage: $coachingAppData.currentIndex, coachingResponse: $coachingAppData.corrections) } } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift index 6ba652f1..5b85e9d5 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift @@ -8,11 +8,20 @@ import Foundation struct CoachingAppData { + var currentIndex: Int var diaryText: String var corrections: [CoachingResponse] var correctResultText: String } +enum CoachingAmplitude { + case coachingButtonTapped(Bool) + case exitButtonTapped(Bool) + case coachingLoading + case coachingResult + case coachingSwipe(Int) +} + final class CoachingStore: Store, ObservableObject { var service: CoachingServiceProtocol @@ -27,11 +36,13 @@ final class CoachingStore: Store, ObservableObject { enum Action { case detailDiaryAPI(diaryID: Int) case coachingButton(diaryID: Int) + case amplitudeInput(type: CoachingAmplitude) } struct State { var detailDiaryResponse = DetailDiaryResponse.empty - var coachingAppData = CoachingAppData(diaryText: "", + var coachingAppData = CoachingAppData(currentIndex: 0, + diaryText: "", corrections: CoachingsResponse.sample.corrections, correctResultText: "첨삭 중이에요") var toastErrorMessage: SmeemError? = nil @@ -63,7 +74,8 @@ final class CoachingStore: Store, ObservableObject { do { state.hiddenIndex += 1 let coachingResponse = try await service.coachingPostAPI(diaryID: ID) - state.coachingAppData = CoachingAppData(diaryText: combineCorrectionText(coachingResponse.corrections), + state.coachingAppData = CoachingAppData(currentIndex: 0, + diaryText: combineCorrectionText(coachingResponse.corrections), corrections: filiterCorrection(coachingResponse.corrections), correctResultText: correctTextResult(coachingResponse.corrections.count)) state.hiddenIndex += 1 @@ -73,6 +85,19 @@ final class CoachingStore: Store, ObservableObject { state.hiddenIndex = 0 } } + case .amplitudeInput(let type): + switch type { + case .coachingButtonTapped(let isActive): + AmplitudeManager.shared.track(event: AmplitudeConstant.coaching.coaching_try_click(isActive).event) + case .exitButtonTapped(let isActive): + AmplitudeManager.shared.track(event: AmplitudeConstant.coaching.coaching_exit_click(isActive).event) + case .coachingLoading: + AmplitudeManager.shared.track(event: AmplitudeConstant.coaching.coaching_load_view.event) + case .coachingResult: + AmplitudeManager.shared.track(event: AmplitudeConstant.coaching.coaching_result_view.event) + case .coachingSwipe(let index): + AmplitudeManager.shared.track(event: AmplitudeConstant.coaching.coaching_feedback_view(index+1).event) + } } } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/View/CoachingView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/View/CoachingView.swift index 1d330497..a1f27ac1 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/View/CoachingView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/View/CoachingView.swift @@ -19,6 +19,7 @@ struct CoachingView: View { HStack() { Spacer() Button(action: { + store.send(action: .amplitudeInput(type: .exitButtonTapped(store.state.isEnabled))) let homeVC = HomeViewController() homeVC.handlePostDiaryAPI(with: store.state.diaryResponse) changeRootViewController(homeVC) @@ -37,6 +38,7 @@ struct CoachingView: View { Button(action: { if store.state.isEnabled { store.send(action: .coachingButton(diaryID: store.state.diaryResponse.diaryID)) + store.send(action: .amplitudeInput(type: .coachingButtonTapped(store.state.isEnabled))) } }) { HStack { @@ -77,6 +79,9 @@ struct CoachingView: View { LottieView("smeemLoading") .loopMode(.loop) .frame(width: screenWidth, height: 164, alignment: .center) + .onAppear { + store.send(action: .amplitudeInput(type: .coachingLoading)) + } Text("AI 코치가 내 일기를 분석하고 있어요\n잠시만 기다려주세요") .font(Font.custom("Pretendard", size: 16)) @@ -87,6 +92,13 @@ struct CoachingView: View { // MARK: 첨삭 화면 } else { CoachingCompleteView(coachingAppData: $store.state.coachingAppData) + .onAppear { + store.send(action: .amplitudeInput(type: .coachingResult)) + store.send(action: .amplitudeInput(type: .coachingSwipe(1))) + } + .onChange(of: store.state.coachingAppData.currentIndex) { index in + store.send(action: .amplitudeInput(type: .coachingSwipe(index))) + } } // MARK: 첫 진입시 토스트뷰 실행 From c3c44e3e89a012d52fce043557ad8f9a44f2bda1 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Wed, 11 Dec 2024 18:34:28 +0900 Subject: [PATCH 27/37] =?UTF-8?q?[Fix]=20#233=20-=20=EB=84=A4=EB=B9=84?= =?UTF-8?q?=EA=B2=8C=EC=9D=B4=EC=85=98=20=EC=8A=A4=ED=83=9D=20=EC=9D=B4?= =?UTF-8?q?=EC=8A=88,=20=EC=BD=94=EC=B9=AD=20filter=20=EB=B0=8F=20?= =?UTF-8?q?=EB=B0=94=EC=9D=B8=EB=94=A9=20=EC=9D=B4=EC=8A=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Global/Extensions/SwiftUI/View+.swift | 3 +- .../Global/Extensions/UIViewController+.swift | 9 ++- .../SwiftUI/CoachingContentView.swift | 56 +++---------------- .../SwiftUI/CustomSegmentedControl.swift | 5 +- .../SwiftUI/SwiftUINavigationView.swift | 9 ++- .../DetailDiary/DetailDiaryCoachedView.swift | 42 ++++++++------ 6 files changed, 49 insertions(+), 75 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift b/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift index 4af09b2c..b34b803a 100644 --- a/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift +++ b/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift @@ -81,7 +81,8 @@ extension View { if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let window = windowScene.windows.first { - window.rootViewController = viewControllerToPresent + let navigationController = UINavigationController(rootViewController: viewControllerToPresent) + window.rootViewController = navigationController UIView.transition(with: window, duration: 0.5, diff --git a/Smeem-iOS/Smeem-iOS/Global/Extensions/UIViewController+.swift b/Smeem-iOS/Smeem-iOS/Global/Extensions/UIViewController+.swift index ff5331ab..7782617d 100644 --- a/Smeem-iOS/Smeem-iOS/Global/Extensions/UIViewController+.swift +++ b/Smeem-iOS/Smeem-iOS/Global/Extensions/UIViewController+.swift @@ -74,8 +74,13 @@ extension UIViewController { func changeRootViewControllerAndPresent(_ viewControllerToPresent: UIViewController) { if let window = UIApplication.shared.windows.first { - window.rootViewController = viewControllerToPresent - UIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve, animations: nil) + let navigationController = UINavigationController(rootViewController: viewControllerToPresent) + window.rootViewController = navigationController + + UIView.transition(with: window, + duration: 0.5, + options: .transitionCrossDissolve, + animations: nil) } else { viewControllerToPresent.modalPresentationStyle = .overFullScreen self.present(viewControllerToPresent, animated: true, completion: nil) diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift index 80036776..36a82153 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CoachingContentView.swift @@ -9,8 +9,8 @@ import SwiftUI struct CoachingContentView: View { @Binding var currentIndex: Int - @Binding var coachingsResponse: CoachingsResponse - @Binding var coachingResponse: [CoachingResponse] + @Binding var detailDiaryResponse: DetailDiaryResponse + @Binding var corrections: [CoachingResponse] var body: some View { VStack(spacing: 20.scaledByHeight()) { @@ -19,11 +19,11 @@ struct CoachingContentView: View { .foregroundStyle(Color(UIColor.gray100)) TabView(selection: $currentIndex) { - ForEach(coachingResponse.indices, id: \.self) { item in + ForEach(corrections.indices, id: \.self) { item in ScrollView { VStack(spacing: 8.scaledByHeight()) { - CoachingComparisonView(coachingResponse: $coachingResponse[item]) - CoachingExplanationView(coachingResponse: $coachingResponse[item]) + CoachingComparisonView(coachingResponse: $corrections[item]) + CoachingExplanationView(coachingResponse: $corrections[item]) } } } @@ -32,52 +32,14 @@ struct CoachingContentView: View { .tabViewStyle(.page(indexDisplayMode: .never)) .padding(.horizontal, 16.scaledByWidth()) - PageControl(currentPage: $currentIndex, coachingResponse: $coachingResponse) + PageControl(currentPage: $currentIndex, coachingResponse: $corrections) } } } -#Preview { - @State var defaultIndex: Int = 0 - @State var coachingsResponse = CoachingsResponse.empty - @State var coachingResponse = CoachingsResponse.empty.corrections - CoachingContentView(currentIndex: $defaultIndex, coachingsResponse: $coachingsResponse, coachingResponse: $coachingResponse) -} - -// -//struct CoachingContentView: View { -// @Binding var currentIndex: Int -// @Binding var coachingResponse: CoachingsResponse -// -// var body: some View { -// VStack(spacing: screenHeight * (20 / screenHeight)) { -// Rectangle() -// .frame(height: screenHeight * (8 / screenHeight)) -// .foregroundStyle(Color(UIColor.gray100)) -// -// TabView(selection: $currentIndex) { -// ForEach(coachingResponse.corrections.indices, id: \.self) { item in -// ScrollView { -// VStack(spacing: screenWidth * (8 / screenWidth)) { -// CoachingComparisonView(coachingResponse: $coachingResponse.corrections[item]) -// -// CoachingExplanationView(coachingResponse: $coachingResponse.corrections[item]) -// } -// } -// } -// } -// .frame(width: screenWidth, height: screenHeight * (286 / screenHeight), alignment: .top) -// .tabViewStyle(.page(indexDisplayMode: .never)) -// .padding(.horizontal, screenWidth * (16 / screenWidth)) -// -// PageControl(currentPage: $currentIndex, -// coachingResponse: $coachingResponse) -// } -// } -//} -// //#Preview { // @State var defaultIndex: Int = 0 -// @State var coachingResponse = CoachingsResponse.empty -// CoachingContentView(currentIndex: $defaultIndex, coachingResponse: $coachingResponse) +// @State var coachingsResponse = CoachingsResponse.empty +// @State var coachingResponse = CoachingsResponse.empty.corrections +// CoachingContentView(currentIndex: $defaultIndex, coachingsResponse: $coachingsResponse, coachingResponse: $coachingResponse) //} diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift index a231392a..f888b88f 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift @@ -23,12 +23,11 @@ struct CustomSegmentedControl: View { ) } } - .background(Color.gray.opacity(0.2)) +// .background(Color.gray.opacity(0.2)) .cornerRadius(6) } private func isCoachingOn(_ index: Int) -> Bool { - // "코칭 ON"일 때만 selected 상태로 처리 return options[index] == "코칭 ON" && selectedIndex == index } } @@ -51,12 +50,10 @@ struct SegmentButton: View { .font(Font(UIFont.c5)) .overlay( Group { - // 'isSelected'일 때만 'isFirstButton'에 오버레이 추가 if isSelected && isFirstButton { CustomStrokeShape(includeLeadingCorners: false) .stroke(Color(UIColor.gray500), lineWidth: 1) } else if !isSelected { - // 'isSelected'가 아닐 때는 모든 버튼에 대해 모서리 처리 CustomStrokeShape( includeLeadingCorners: isFirstButton, includeTrailingCorners: isLastButton diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift index 6a9a7a3b..387097cf 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/SwiftUINavigationView.swift @@ -35,19 +35,18 @@ struct SwiftUINavigationView: View { navigationViewModel.leftButtonTapped.send() }, label: { Image("icnBack") - .imageScale(.large) }) .padding(.leading, 12.scaledByWidth()) } else { Spacer().frame(width: 30.scaledByWidth()) } - // 중앙 콘텐츠 (CustomSegmentedControl) + // CustomSegmentedControl if navigationbarType == .diaryDetails { CustomSegmentedControl(selectedIndex: $selectedIndex, options: options) .frame(height: 32.scaledByHeight()) - .padding(.leading, 65.scaledByWidth()) - .padding(.trailing, 59.scaledByWidth()) + .padding(.leading, 64.scaledByWidth()) + .padding(.trailing, 58.scaledByWidth()) } Spacer() @@ -78,6 +77,6 @@ struct SwiftUINavigationView: View { @State var defaultIndex = 0 NavigationView { - SwiftUINavigationView(navigationViewModel: NavigationViewModel(), selectedIndex: $defaultIndex, navigationbarType: .unCoached) + SwiftUINavigationView(navigationViewModel: NavigationViewModel(), selectedIndex: $defaultIndex, navigationbarType: .diaryDetails) } } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index 3272878d..db7a72a4 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -10,11 +10,9 @@ import SwiftUI import UIKit struct DetailDiaryCoachedView: View { - @StateObject private var navigationViewModel = NavigationViewModel() @State private var cancelBag = Set() - @State private var coachingsResponse = CoachingsResponse(corrections: []) @State private var response: DetailDiaryResponse? @State private var isLoading = false @State private var onError = false @@ -24,6 +22,7 @@ struct DetailDiaryCoachedView: View { @State var diaryContent = "" @State var randomTopic = "" @State var currentIndex = 0 + @State private var filteredCorrections: [CoachingResponse] = [] @State private var isShowingFloatingButtons = false @State private var selectedIndex = 0 @State private var navigationbarType: NavigationbarType = .diaryDetails @@ -78,7 +77,7 @@ struct DetailDiaryCoachedView: View { if let response = response { ScrollableDiaryView( diaryText: response.content, - corrections: response.corrections, + corrections: filteredCorrections, currentIndex: currentIndex, selectedIndex: selectedIndex, dateText: response.createdAt, @@ -86,21 +85,25 @@ struct DetailDiaryCoachedView: View { ) } else { if isLoading { - ProgressView("Loading...") + SmemeEmptyView() + SmemeLoadingView() } } // "코칭 ON"일 때만 표시 if selectedIndex == 1 { - Spacer() - CoachingContentView( - currentIndex: $currentIndex, - coachingsResponse: $coachingsResponse, - coachingResponse: $coachingsResponse.corrections - ) - } else { - Spacer(minLength: 342.scaledByHeight()) - } + Spacer() + CoachingContentView( + currentIndex: $currentIndex, + detailDiaryResponse: Binding( + get: { self.response ?? .empty }, + set: { _ in } + ), + corrections: $filteredCorrections + ) + } else { + Spacer(minLength: 342.scaledByHeight()) + } } .onAppear { Task { @@ -128,6 +131,14 @@ struct DetailDiaryCoachedView: View { } } } +} + +// MARK: - Extension + +extension DetailDiaryCoachedView { + func filterCorrection(_ response: DetailDiaryResponse) -> [CoachingResponse] { + return response.corrections.filter { $0.isCorrected }.prefix(10).map{$0} + } private func navigateToEditDiary() { let editVC = EditDiaryViewController() @@ -147,10 +158,9 @@ struct DetailDiaryCoachedView: View { self.diaryContent = response.content self.randomTopic = response.topic - let corrections = response.corrections ?? [] - self.coachingsResponse = CoachingsResponse(corrections: corrections) + self.filteredCorrections = filterCorrection(response) - if corrections.isEmpty { + if filteredCorrections.isEmpty { navigationbarType = .unCoached } From d6b6a33b828457a715dc741e82a5857e5128d9dc Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Wed, 11 Dec 2024 19:34:03 +0900 Subject: [PATCH 28/37] =?UTF-8?q?[Fix]=20#241=20-=20CustomSegmentedControl?= =?UTF-8?q?=20UI=20=EC=9D=B4=EC=8A=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Global/UIComponents/SwiftUI/CustomSegmentedControl.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift index f888b88f..7c18cfa4 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift @@ -43,11 +43,13 @@ struct SegmentButton: View { Button(action: action) { Text(title) .padding(.vertical, 8.scaledByHeight()) - .padding(.horizontal, 11.scaledByWidth()) + .padding(.horizontal, 10.scaledByWidth()) .frame(maxWidth: .infinity) .background(backgroundColor) .foregroundColor(foregroundColor) .font(Font(UIFont.c5)) +// .lineLimit(1) +// .minimumScaleFactor(0.9) .overlay( Group { if isSelected && isFirstButton { From 585ffa248dddd18d4e2312db26bba533e71a0a20 Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Wed, 11 Dec 2024 23:27:00 +0900 Subject: [PATCH 29/37] =?UTF-8?q?[CHORE]=20#239=20-=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=ED=8C=9D=EC=97=85=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Splah/ViewModel/SplashViewModel.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift b/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift index 1949b5f1..695fa664 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift @@ -147,5 +147,23 @@ extension SplashViewModel { return false } } + + func checkVersion2(client: String, now: String, force: String) -> Bool { + let clientVersion = client.split(separator: ".").map{$0} + let nowVersion = now.split(separator: ".").map{$0} + let forceVersion = force.split(separator: ".").map{$0} + + // x 버전이 더 크면 강제 업데이트 + if forceVersion[0] > clientVersion[0] { + return true + // x 버전이 같고, y 버전이 더 크면 강제 업데이트 + } else if forceVersion[0] == clientVersion[0] && forceVersion[1] > clientVersion[1] { + return true + // x, y 버전이 같고, z버전이 더 크면 강제 업데이트 + } else if (forceVersion[0] == clientVersion[0] && forceVersion[1] > clientVersion[1]) && forceVersion[2] > clientVersion[2] { + return true + } + return false + } } From 9ffc1be9c0ec9d9ee7a5847ac072015a0001f888 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Thu, 12 Dec 2024 01:29:53 +0900 Subject: [PATCH 30/37] =?UTF-8?q?[Feat]=20#241=20-=20RandomTopicSwiftUI=20?= =?UTF-8?q?View=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EB=B0=94=EC=9D=B8=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SwiftUI/RandomTopicViewSwiftUI.swift | 45 +++++++++++++++++++ .../DetailDiary/DetailDiaryCoachedView.swift | 15 ++++++- 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/RandomTopicViewSwiftUI.swift diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/RandomTopicViewSwiftUI.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/RandomTopicViewSwiftUI.swift new file mode 100644 index 00000000..82dc1adb --- /dev/null +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/RandomTopicViewSwiftUI.swift @@ -0,0 +1,45 @@ +// +// RandomTopicViewSwiftUI.swift +// Smeem-iOS +// +// Created by Joon Baek on 12/11/24. +// + +import SwiftUI + +struct RandomTopicViewSwiftUI: View { + + // MARK: - Properties + + var contentText: String? + + // MARK: - Body + + var body: some View { + GeometryReader { geometry in + HStack(alignment: .firstTextBaseline, spacing: 3) { + Text("Q.") + .font(Font(UIFont.b1)) + .foregroundColor(Color(UIColor.point)) + .padding(.leading, 18.scaledByWidth()) + + Text(contentText ?? "") + .font(Font(UIFont.b4)) + .foregroundColor(Color(UIColor.smeemBlack)) + .lineLimit(2) + .fixedSize(horizontal: false, vertical: true) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.trailing, 30.scaledByWidth()) + } + .padding(.top, 20.scaledByHeight()) + .padding(.bottom, 20.scaledByHeight()) + .background(Color(UIColor.gray100)) + } + .frame(height: contentText?.count ?? 0 > 20 ? 84.scaledByHeight() : 62.scaledByHeight()) + } +} + +#Preview { + var text: String = "랜덤주제 한줄일 경우 " + RandomTopicViewSwiftUI(contentText: text) +} diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index db7a72a4..9fd3126a 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -10,6 +10,9 @@ import SwiftUI import UIKit struct DetailDiaryCoachedView: View { + + // MARK: - Properties + @StateObject private var navigationViewModel = NavigationViewModel() @State private var cancelBag = Set() @@ -33,8 +36,10 @@ struct DetailDiaryCoachedView: View { private let detailDiaryService = DetailDiaryService.shared + // MARK: - Body + var body: some View { - VStack(spacing: 16.scaledByWidth()) { + VStack(spacing: 0) { SwiftUINavigationView(navigationViewModel: navigationViewModel, selectedIndex: $selectedIndex, navigationbarType: navigationbarType @@ -74,6 +79,12 @@ struct DetailDiaryCoachedView: View { } } + if let topic = response?.topic { + if topic != "" { + RandomTopicViewSwiftUI(contentText: response?.topic) + } + } + if let response = response { ScrollableDiaryView( diaryText: response.content, @@ -102,7 +113,7 @@ struct DetailDiaryCoachedView: View { corrections: $filteredCorrections ) } else { - Spacer(minLength: 342.scaledByHeight()) + Spacer() } } .onAppear { From f0c3c44de384516aef731272e262b35f0a00d960 Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Thu, 12 Dec 2024 11:40:23 +0900 Subject: [PATCH 31/37] =?UTF-8?q?[FEAT]=20#241=20-=20=EC=BD=94=EC=B9=AD=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=EC=9D=BC=EA=B8=B0?= =?UTF-8?q?=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20text,=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EB=B6=84=EA=B8=B0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/CoachingCompleteView.swift | 39 +++++++++++-------- .../Coaching/Store/CoachingStore.swift | 12 +++--- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift index 77b9d86b..1758233a 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Components/CoachingCompleteView.swift @@ -34,7 +34,9 @@ struct CoachingCompleteView: View { highlightIndex: currentIndex )) .font(Font.custom("Pretendard", size: 16)) - .foregroundColor(Color(UIColor.gray400)) + .foregroundColor(coachingAppData.corrections.isEmpty + ? Color(UIColor.black) + : Color(UIColor.gray400)) .lineSpacing(0.375) Spacer() @@ -46,26 +48,29 @@ struct CoachingCompleteView: View { } .padding(.horizontal, screenWidth * 0.048) - VStack(spacing: 20) { - Rectangle() - .frame(height: 8) - .foregroundStyle(Color(UIColor.gray100)) - TabView(selection: $currentIndex) { - ForEach(coachingAppData.corrections.indices, id: \.self) { item in - ScrollView { - VStack(spacing: 8) { - CoachingComparisonView(coachingResponse: $coachingAppData.corrections[item]) - - CoachingExplanationView(coachingResponse: $coachingAppData.corrections[item]) + // 코칭 일기가 있을 때만 보여짐. + if !coachingAppData.corrections.isEmpty { + VStack(spacing: 20) { + Rectangle() + .frame(height: 8) + .foregroundStyle(Color(UIColor.gray100)) + TabView(selection: $currentIndex) { + ForEach(coachingAppData.corrections.indices, id: \.self) { item in + ScrollView { + VStack(spacing: 8) { + CoachingComparisonView(coachingResponse: $coachingAppData.corrections[item]) + + CoachingExplanationView(coachingResponse: $coachingAppData.corrections[item]) + } } } } + .frame(width: screenWidth, height: screenHeight * (326/screenHeight), alignment: .top) + .tabViewStyle(.page(indexDisplayMode: .never)) + + PageControl(currentPage: $currentIndex, + coachingResponse: $coachingAppData.corrections) } - .frame(width: screenWidth, height: screenHeight * (326/screenHeight), alignment: .top) - .tabViewStyle(.page(indexDisplayMode: .never)) - - PageControl(currentPage: $currentIndex, - coachingResponse: $coachingAppData.corrections) } } } diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift index 6ba652f1..7b0b85c0 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Coaching/Store/CoachingStore.swift @@ -64,8 +64,8 @@ final class CoachingStore: Store, ObservableObject { state.hiddenIndex += 1 let coachingResponse = try await service.coachingPostAPI(diaryID: ID) state.coachingAppData = CoachingAppData(diaryText: combineCorrectionText(coachingResponse.corrections), - corrections: filiterCorrection(coachingResponse.corrections), - correctResultText: correctTextResult(coachingResponse.corrections.count)) + corrections: filiterCorrection(coachingResponse.corrections) ?? [], + correctResultText: correctTextResult(filiterCorrection(coachingResponse.corrections) ?? [])) state.hiddenIndex += 1 } catch let error { let error = error as? SmeemError @@ -80,12 +80,12 @@ final class CoachingStore: Store, ObservableObject { return response.map{ $0.originalSentence }.joined(separator: " ") } - func filiterCorrection(_ response: [CoachingResponse]) -> [CoachingResponse] { + func filiterCorrection(_ response: [CoachingResponse]) -> [CoachingResponse]? { return response.filter { $0.isCorrected }.prefix(10).map{$0} } - func correctTextResult(_ count: Int) -> String { - switch count { + func correctTextResult(_ response: [CoachingResponse]) -> String { + switch response.count { case 0: return "완벽한 일기예요!👍\n문장이 자연스럽고 오류가 없어요" case 1: @@ -93,7 +93,7 @@ final class CoachingStore: Store, ObservableObject { case 2...: return "대단해요!🥳🎉\n몇 가지 피드백을 준비해 봤어요." default: - return "대단해요!🥳🎉\n몇 가지 피드백을 준비해 봤어요." + return "완벽한 일기예요!👍\n문장이 자연스럽고 오류가 없어요" } } } From 0158198b4f3961d4a5d4d55f073f755ef1a780d0 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Thu, 12 Dec 2024 11:41:30 +0900 Subject: [PATCH 32/37] =?UTF-8?q?[Fix]=20#241-=20=EC=B7=A8=EC=86=8C?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EA=B4=80=EB=A0=A8=20=EC=9D=B4=EC=8A=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift | 7 ++++++- .../Presentation/DetailDiary/DetailDiaryCoachedView.swift | 4 +--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift b/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift index b34b803a..20560d41 100644 --- a/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift +++ b/Smeem-iOS/Smeem-iOS/Global/Extensions/SwiftUI/View+.swift @@ -35,7 +35,12 @@ extension View { ) alert.addAction(UIAlertAction(title: firstActionTitle, style: .cancel) { _ in - firstActionHandler?() + // 현재 presenting view controller를 찾아서 dismiss + if let presentedViewController = UIApplication.shared.windows.first?.rootViewController?.presentedViewController { + presentedViewController.dismiss(animated: true) { + firstActionHandler?() + } + } }) alert.addAction(UIAlertAction(title: secondActionTitle, style: .default) { _ in diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index 9fd3126a..30fa5300 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -58,9 +58,7 @@ struct DetailDiaryCoachedView: View { message: "수정시 모든 코칭 내용이 사라집니다. 그래도 수정하시겠습니까?", firstActionTitle: "취소", secondActionTitle: "확인", - firstActionHandler: { - dismiss() - }, + firstActionHandler: { }, secondActionHandler: { navigateToEditDiary() } From e765d2e7d147eb0a914b8d35adced90fa6237638 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Thu, 12 Dec 2024 12:18:24 +0900 Subject: [PATCH 33/37] =?UTF-8?q?[Fix]=20#239=20-=20SegmentedControl=20?= =?UTF-8?q?=ED=8F=B0=ED=8A=B8=20=EA=B9=A8=EC=A7=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Global/UIComponents/SwiftUI/CustomSegmentedControl.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift index 7c18cfa4..52eabd3f 100644 --- a/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift +++ b/Smeem-iOS/Smeem-iOS/Global/UIComponents/SwiftUI/CustomSegmentedControl.swift @@ -49,7 +49,7 @@ struct SegmentButton: View { .foregroundColor(foregroundColor) .font(Font(UIFont.c5)) // .lineLimit(1) -// .minimumScaleFactor(0.9) + .minimumScaleFactor(0.9) .overlay( Group { if isSelected && isFirstButton { From 25dc06048a08604eaee693b5afcf747e45b06955 Mon Sep 17 00:00:00 2001 From: Joon Baek Date: Thu, 12 Dec 2024 15:45:46 +0900 Subject: [PATCH 34/37] =?UTF-8?q?[Feat]=20#239=20-=20=EC=9D=BC=EA=B8=B0=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=EB=B3=B4=EA=B8=B0=20=EC=95=B0=ED=94=8C?= =?UTF-8?q?=EB=A6=AC=ED=8A=9C=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DetailDiary/DetailDiaryCoachedView.swift | 16 ++++++++++++++++ .../DetailDiary/DetailDiaryViewController.swift | 1 - .../Controllers/EditDiaryViewController.swift | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift index 30fa5300..8d11396f 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryCoachedView.swift @@ -32,6 +32,9 @@ struct DetailDiaryCoachedView: View { @State private var toastErrorMessage: SmeemError? = nil var toastMessage: SmeemToast? = .completed + var hasCorrections: Bool { + return !(response?.corrections.isEmpty ?? true) + } @Environment(\.dismiss) private var dismiss private let detailDiaryService = DetailDiaryService.shared @@ -67,6 +70,9 @@ struct DetailDiaryCoachedView: View { navigateToEditDiary() } } + .onTapGesture { + AmplitudeManager.shared.track(event: AmplitudeConstant.diaryDetail.mydiary_edit(hasCorrections).event) + } Button("삭제하기", role: .destructive) { deleteDiaryWithAPI(diaryID: diaryID ?? 0) @@ -115,10 +121,15 @@ struct DetailDiaryCoachedView: View { } } .onAppear { + AmplitudeManager.shared.track(event: AmplitudeConstant.diaryDetail.mydiary_view(hasCorrections).event) Task { await fetchCoachingData(diaryID: diaryID ?? 0) } } + .onChange(of: selectedIndex) { newValue in + AmplitudeManager.shared.track(event: AmplitudeConstant.diaryDetail.toggle_click(convertSelectedIndexToString(newValue)).event + ) + } .overlay { if isLoading { SmemeEmptyView() @@ -154,10 +165,15 @@ extension DetailDiaryCoachedView { editVC.diaryID = self.diaryID ?? 0 editVC.randomContent = self.randomTopic editVC.diaryTextView.text = self.diaryContent + editVC.hasCoached = self.hasCorrections editVC.randomSubjectView.setData(contentText: self.randomTopic) self.pushToUIKitView(editVC) } + private func convertSelectedIndexToString(_ index: Int) -> String { + return index == 0 ? "코칭 OFF" : "코칭 ON" + } + @MainActor private func fetchCoachingData(diaryID: Int) async { isLoading = true diff --git a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryViewController.swift b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryViewController.swift index 2d067606..80bad1d1 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryViewController.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/DetailDiary/DetailDiaryViewController.swift @@ -82,7 +82,6 @@ extension DetailDiaryViewController { @objc func showActionSheet() { let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) let modifyAction = UIAlertAction (title: "수정", style: .default, handler: { (action) in - AmplitudeManager.shared.track(event: AmplitudeConstant.diaryDetail.mydiary_edit.event) let editVC = EditDiaryViewController() editVC.diaryID = self.diaryId editVC.randomContent = self.isRandomTopic diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift b/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift index c08adbab..896841ee 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Diaries/View/Controllers/EditDiaryViewController.swift @@ -15,6 +15,7 @@ final class EditDiaryViewController: BaseViewController { var diaryID = Int() var randomContent = String() + var hasCoached = Bool() // MARK: - UI Property @@ -169,6 +170,7 @@ extension EditDiaryViewController { func patchDiaryAPI() { PostDiaryAPI.shared.patchDiary(param: PatchDiaryRequest(content: diaryTextView.text), diaryID: diaryID) { response in DispatchQueue.main.async { + AmplitudeConstant.diaryDetail.mydiary_edit_complete_click(self.hasCoached).event self.changeRootViewControllerAndPresent(HomeViewController()) } } From a33d334e0a39a0bb3c8ebdccd7734e69247a1837 Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Thu, 12 Dec 2024 15:58:14 +0900 Subject: [PATCH 35/37] =?UTF-8?q?[TEST]=20#239=20-=20detail=20diary=20test?= =?UTF-8?q?=20code=20model=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../API/DetailDiary/DetailDiaryEndPoint.swift | 1 + .../DetailDiary/DetailDiaryResponse.swift | 20 ------------------- .../Service/CoachingServiceTest.swift | 1 + .../Coaching/Store/CoachingStoreTest.swift | 8 ++++---- 4 files changed, 6 insertions(+), 24 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Network/API/DetailDiary/DetailDiaryEndPoint.swift b/Smeem-iOS/Smeem-iOS/Network/API/DetailDiary/DetailDiaryEndPoint.swift index e096fc93..d4753066 100644 --- a/Smeem-iOS/Smeem-iOS/Network/API/DetailDiary/DetailDiaryEndPoint.swift +++ b/Smeem-iOS/Smeem-iOS/Network/API/DetailDiary/DetailDiaryEndPoint.swift @@ -55,6 +55,7 @@ extension DetailDiaryEndPoint { "content": "일기 내용입니다", "createdAt": "2024년 5월 18일", "username": "찬미", + "isUpdated": true, "corrections": [ { "originalSentence": "original text", diff --git a/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift b/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift index 971a6baa..16bbe79e 100644 --- a/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift +++ b/Smeem-iOS/Smeem-iOS/Network/NetworkDataModel/DetailDiary/DetailDiaryResponse.swift @@ -21,12 +21,6 @@ struct DetailDiaryResponse: Codable, Equatable { } } -//struct CorrentionsData: Codable { -// let correntionId: Int -// let before: String -// let after: String -//} - extension DetailDiaryResponse { static let empty = DetailDiaryResponse(diaryId: 0, topic: "", content: "테스트임?", createdAt: "그래", username: "그래", isUpdated: true, corrections: [CoachingResponse(originalSentence: "I have went to the park yesterdayI have went to the park yesterdayI have went to the park yesterdayI have went to the park yesterday", correctedSentence: "I went to the park yesterdayI went to the park yesterdayI went to the park yesterdayI went to the park yesterdayI went to the park yesterday", @@ -37,17 +31,3 @@ extension DetailDiaryResponse { reason: "이러 이러한 이유로 이건 맞습니다", isCorrected: true)], correctionCount: 0, correctionMaxCount: 0) } - -//struct CoachingResponse: Codable, Equatable { -// let originalSentence: String -// let correctedSentence: String -// let reason: String -// let isCorrected: Bool -// -// enum CodingKeys: String, CodingKey { -// case originalSentence = "originalSentence" -// case correctedSentence = "correctedSentence" -// case reason -// case isCorrected = "isCorrected" -// } -//} diff --git a/Smeem-iOS/Smeem-iOSTests/Coaching/Service/CoachingServiceTest.swift b/Smeem-iOS/Smeem-iOSTests/Coaching/Service/CoachingServiceTest.swift index cf154ba6..8be821d0 100644 --- a/Smeem-iOS/Smeem-iOSTests/Coaching/Service/CoachingServiceTest.swift +++ b/Smeem-iOS/Smeem-iOSTests/Coaching/Service/CoachingServiceTest.swift @@ -51,6 +51,7 @@ extension CoachingServiceTest { content: "일기 내용입니다", createdAt: "2024년 5월 18일", username: "찬미", + isUpdated: true, corrections: [CoachingResponse(originalSentence: "original text", correctedSentence: "corrected text", reason: "수정된 문구입니다.", diff --git a/Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift b/Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift index f03c754c..cc408a58 100644 --- a/Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift +++ b/Smeem-iOS/Smeem-iOSTests/Coaching/Store/CoachingStoreTest.swift @@ -59,7 +59,7 @@ final class CoachingStoreTest: XCTestCase { isCorrected: false)) } - var expectedResult = [CoachingResponse]() + let expectedResult = [CoachingResponse]() // When let outputResult = sut.filiterCorrection(filterResult) @@ -71,14 +71,14 @@ final class CoachingStoreTest: XCTestCase { func test_원문일기_잘조합해주는지() { // Given var filterResult = [CoachingResponse]() - for i in 1...3 { - filterResult.append(CoachingResponse(originalSentence: "안녕", + for _ in 1...3 { + filterResult.append(CoachingResponse(originalSentence: "테스트", correctedSentence: "", reason: "", isCorrected: false)) } - var expectedResult = "안녕 안녕 안녕" + let expectedResult = "테스트 테스트 테스트" // When let outputResult = sut.combineCorrectionText(filterResult) From 69905b7723e8e0060daec793bde53290d186985b Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Thu, 12 Dec 2024 16:03:00 +0900 Subject: [PATCH 36/37] =?UTF-8?q?[CHORE]=20#239=20-=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=EB=B2=84=EC=A0=84=20=EB=B0=8F=20=EB=B9=8C?= =?UTF-8?q?=EB=93=9C=20=EB=B2=84=EC=A0=84=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj | 6 ++-- .../Splah/ViewModel/SplashViewModel.swift | 35 +++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj index 4c28789a..cb6df42b 100644 --- a/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj +++ b/Smeem-iOS/Smeem-iOS.xcodeproj/project.pbxproj @@ -2277,7 +2277,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0.3; + MARKETING_VERSION = 3.0.0; PRODUCT_BUNDLE_IDENTIFIER = "Team.Smeem-dev"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2299,7 +2299,7 @@ CODE_SIGN_ENTITLEMENTS = "Smeem-iOS/Smeem-iOS.entitlements"; CODE_SIGN_IDENTITY = "Apple Distribution: YuJi Lee (K8LLWYQWXD)"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 20241031; + CURRENT_PROJECT_VERSION = 2024121201; DEVELOPMENT_TEAM = K8LLWYQWXD; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "Smeem-iOS/Info.plist"; @@ -2315,7 +2315,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0.3; + MARKETING_VERSION = 3.0.0; PRODUCT_BUNDLE_IDENTIFIER = "Team.Smeem-iOS"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = smeem_release; diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift b/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift index 695fa664..201630f9 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift @@ -52,7 +52,6 @@ final class SplashViewModel: ViewModel { switch result { case .success(let response): if self.checkVersion(client: self.appVersion, - now: response.iosVersion.version, force: response.iosVersion.forceVersion) { promise(.success(UpdateTextModel(title: response.title, @@ -133,24 +132,8 @@ final class SplashViewModel: ViewModel { } extension SplashViewModel { - func checkVersion(client: String, now: String, force: String) -> Bool { + func checkVersion(client: String, force: String) -> Bool { let clientVersion = client.split(separator: ".").map{$0} - let nowVersion = now.split(separator: ".").map{$0} - let forceVersion = force.split(separator: ".").map{$0} - - // force가 크고 현재 앱 버전이랑 now랑 다를 때 -> 강업 - if forceVersion[0] > clientVersion[0] && clientVersion != nowVersion { - return true - } else { - // force가 크고, 현재 앱 버전이랑 now랑 같을 때 -> 강업하고 온 유저 - // force가 안 큼 -> 강업할 필요 없는 상태 - return false - } - } - - func checkVersion2(client: String, now: String, force: String) -> Bool { - let clientVersion = client.split(separator: ".").map{$0} - let nowVersion = now.split(separator: ".").map{$0} let forceVersion = force.split(separator: ".").map{$0} // x 버전이 더 크면 강제 업데이트 @@ -165,5 +148,21 @@ extension SplashViewModel { } return false } + + func checkVersion2(client: String, now: String, force: String) -> Bool { + let clientVersion = client.split(separator: ".").map{$0} + let nowVersion = now.split(separator: ".").map{$0} + let forceVersion = force.split(separator: ".").map{$0} + + // force가 크고 현재 앱 버전이랑 now랑 다를 때 -> 강업 + if forceVersion[0] > clientVersion[0] && clientVersion != nowVersion { + return true + } else { + // force가 크고, 현재 앱 버전이랑 now랑 같을 때 -> 강업하고 온 유저 + // force가 안 큼 -> 강업할 필요 없는 상태 + return false + } + } + } From 8ad8e0f825d0b334672a9e3818e52ce1cfa5d473 Mon Sep 17 00:00:00 2001 From: cchanmi <113524@naver.com> Date: Thu, 12 Dec 2024 16:19:29 +0900 Subject: [PATCH 37/37] =?UTF-8?q?[TEST]=20#239=20-=20=EA=B0=95=EC=A0=9C=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Splash/Splah/ViewModel/SplashViewModel.swift | 2 +- .../Onboarding/ViewModel/SplashViewModelTest.swift | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift b/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift index 201630f9..f1cc663e 100644 --- a/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift +++ b/Smeem-iOS/Smeem-iOS/Presentation/Splash/Splah/ViewModel/SplashViewModel.swift @@ -10,7 +10,7 @@ import Combine final class SplashViewModel: ViewModel { - private let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String + let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String struct Input { let checkUpdatePopup: PassthroughSubject diff --git a/Smeem-iOS/Smeem-iOSTests/Onboarding/ViewModel/SplashViewModelTest.swift b/Smeem-iOS/Smeem-iOSTests/Onboarding/ViewModel/SplashViewModelTest.swift index 0e784a7d..24f72215 100644 --- a/Smeem-iOS/Smeem-iOSTests/Onboarding/ViewModel/SplashViewModelTest.swift +++ b/Smeem-iOS/Smeem-iOSTests/Onboarding/ViewModel/SplashViewModelTest.swift @@ -14,15 +14,17 @@ final class SplashViewModelTest: XCTestCase { private var viewModel: SplashViewModel! private var mockService: SplashServiceMock! + private var appVersion: String! override func setUpWithError() throws { self.mockService = SplashServiceMock() self.viewModel = SplashViewModel(provider: mockService) + self.appVersion = viewModel.appVersion } func test_강제업데이트안한유저_정확한데이터_return하는지() { // Given - let result = self.viewModel.checkVersion(client: "2.0.0", now: "2.0.1", force: "3.0.0") + let result = self.viewModel.checkVersion(client: "2.0.3", force: "3.0.0") // When let expectedResult = true @@ -33,7 +35,7 @@ final class SplashViewModelTest: XCTestCase { func test_강제업데이트로하고온유저_정확한데이터_return하는지() { // Given - let result = self.viewModel.checkVersion(client: "2.0.1", now: "2.0.1", force: "3.0.0") + let result = self.viewModel.checkVersion(client: self.appVersion, force: "3.0.0") // When let expectedResult = false @@ -42,12 +44,12 @@ final class SplashViewModelTest: XCTestCase { XCTAssertEqual(result, expectedResult) } - func test_강제업데이트하지않아도되는유저_정확한데이터_return하는지() { + func test_이전업데이트로직유저_강제업데이트팝업잘뜨는지() { // Given - let result = self.viewModel.checkVersion(client: "2.0.1", now: "2.0.1", force: "2.0.0") + let result = self.viewModel.checkVersion2(client: "2.0.3", now: "2.0.4", force: "3.0.0") // When - let expectedResult = false + let expectedResult = true // Then XCTAssertEqual(result, expectedResult)