Skip to content

Commit

Permalink
✨ :: 운동챗봇뷰 구현 #KAN-321-1
Browse files Browse the repository at this point in the history
  • Loading branch information
uk10105 committed Aug 8, 2024
1 parent 61070f8 commit 7438b97
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 35 deletions.
4 changes: 4 additions & 0 deletions Frontend-iOS/FebirdApp/FebirdApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
E208BDEE2C62952F0094CC16 /* DailyMemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E208BDED2C62952F0094CC16 /* DailyMemo.swift */; };
E208BDF02C6295660094CC16 /* MealMemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E208BDEF2C6295660094CC16 /* MealMemo.swift */; };
E20F9CF82C63DEA9006A034B /* ChatTextFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20F9CF72C63DEA9006A034B /* ChatTextFieldView.swift */; };
E20F9D052C6475F8006A034B /* TextFieldTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E20F9D042C6475F8006A034B /* TextFieldTest.swift */; };
E246A8DE2C5EAAF600B86617 /* ExerciseChatBotView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E246A8DD2C5EAAF600B86617 /* ExerciseChatBotView.swift */; };
E246A8E02C5EC4A200B86617 /* ExerciseCountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E246A8DF2C5EC4A200B86617 /* ExerciseCountView.swift */; };
E24CF94E2C4F887100D1548E /* CustomToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24CF94D2C4F887100D1548E /* CustomToggle.swift */; };
Expand Down Expand Up @@ -298,6 +299,7 @@
E208BDED2C62952F0094CC16 /* DailyMemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyMemo.swift; sourceTree = "<group>"; };
E208BDEF2C6295660094CC16 /* MealMemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealMemo.swift; sourceTree = "<group>"; };
E20F9CF72C63DEA9006A034B /* ChatTextFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatTextFieldView.swift; sourceTree = "<group>"; };
E20F9D042C6475F8006A034B /* TextFieldTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldTest.swift; sourceTree = "<group>"; };
E241DB512C63864600F4BFC8 /* Secret.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Secret.xcconfig; sourceTree = "<group>"; };
E246A8DD2C5EAAF600B86617 /* ExerciseChatBotView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseChatBotView.swift; sourceTree = "<group>"; };
E246A8DF2C5EC4A200B86617 /* ExerciseCountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseCountView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -486,6 +488,7 @@
8F92DF822C4BB0970071F336 /* VideoPlayerView.swift */,
8F0F47DB2C636BF6004E3B86 /* Config.swift */,
E20F9CF72C63DEA9006A034B /* ChatTextFieldView.swift */,
E20F9D042C6475F8006A034B /* TextFieldTest.swift */,
);
path = Utils;
sourceTree = "<group>";
Expand Down Expand Up @@ -1060,6 +1063,7 @@
E20F9CF82C63DEA9006A034B /* ChatTextFieldView.swift in Sources */,
E2EB25792C4E48C30094EC8E /* ChatBotMainView.swift in Sources */,
8F92DF912C4D68B40071F336 /* ExerciseRoutineLogView.swift in Sources */,
E20F9D052C6475F8006A034B /* TextFieldTest.swift in Sources */,
E2CFF2122C4E9D6300540500 /* InputFieldView.swift in Sources */,
8F92DF892C4D4A440071F336 /* TimerButton.swift in Sources */,
E15BF0232C6097CC0033E5C3 /* JointOverlayView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,57 +12,63 @@ struct ExerciseChatBotView: View {
@EnvironmentObject var exerciseNavigationPathFinder: NavigationPathFinder<ExerciseViewOptions>
@StateObject private var viewModel = ChatViewModel.shared
@State private var inputText = ""
@FocusState private var isTextFieldFocused: Bool
@StateObject private var keyboardHandler = KeyboardHandler()

var body: some View {
VStack {
HStack {
Button {
exerciseNavigationPathFinder.popPath()
tabViewModel.isHidden = false
} label: {
Image("Chevron-left")
}
GeometryReader { geometry in
VStack(spacing: 0) {
// Header
VStack {
HStack {
Button {
exerciseNavigationPathFinder.popPath()
tabViewModel.isHidden = false
} label: {
Image("Chevron-left")
}

HStack {
Spacer()
Spacer()

Text("피오코치")
.font(.customFont(size: 22, weight: .bold))
.foregroundStyle(.gray100)
.padding(.trailing, 16)
Text("피오코치")
.font(.customFont(size: 22, weight: .bold))
.foregroundStyle(.gray100)

Spacer()
Spacer()
}
.padding(.horizontal, 20)
}
}
.padding(16)
.frame(height: 64)
.padding(.top, 100)
.frame(height: 164)
.background(Color.white)
.zIndex(1) // Ensure header stays on top

ScrollView {
LazyVStack(alignment: .leading, spacing: 10) {
ForEach(viewModel.messages, id: \.content) { message in
MessageBubble(message: message)
// Chat area
ScrollView {
LazyVStack(alignment: .leading, spacing: 10) {
ForEach(viewModel.messages, id: \.content) { message in
MessageBubble(message: message)
}
}
.padding()
}
.padding()
.padding(.top, 10) // Add some padding to separate from header
.frame(height: max(0, geometry.size.height - 264 - keyboardHandler.keyboardHeight))

// Input field
TextFieldTest(placeholder: "메시지를 입력하세요", text: $inputText, viewModel: viewModel)
.focused($isTextFieldFocused)
}
// InputFieldView(text: $inputText, viewModel: viewModel)
ChatTextFieldView(placeholder: "메시지를 입력하세요", text: $inputText, keyboardType: .default, viewModel: viewModel)
}
.padding(.top, 60)
.background(
Rectangle()
.foregroundStyle(.white)
)
.background(ignoresSafeAreaEdges: .bottom)
.background(Color.white)
.ignoresSafeArea()
.background(
Rectangle()
.foregroundStyle(.white)
)
.onAppear {
tabViewModel.isHidden = true
}
.navigationBarBackButtonHidden()
.onTapGesture {
isTextFieldFocused = false
}
}
}

Expand Down
76 changes: 76 additions & 0 deletions Frontend-iOS/FebirdApp/FebirdApp/Sources/Utils/TextFieldTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// TextFieldTest.swift
// FebirdApp
//
// Created by 이유경 on 8/8/24.
//

import SwiftUI
import Combine

struct TextFieldTest: View {
var placeholder: String
@Binding var text: String
@FocusState private var isTextFieldFocused: Bool
@ObservedObject var viewModel: ChatViewModel
@StateObject private var keyboardHandler = KeyboardHandler()

var body: some View {
ZStack {
Rectangle()
.foregroundStyle(.white)
.cornerRadius(20, corners: [.topLeft, .topRight])
.frame(maxWidth: .infinity, maxHeight: 100)
.shadow(color: Color.gray20, radius: 5, x: 0, y: 2)

HStack(spacing: 8) {
TextField(placeholder, text: $text)
.focused($isTextFieldFocused)
.padding(.horizontal, 16)
.padding(.vertical, 8)
.frame(height: 56, alignment: .leading)
.foregroundStyle(.gray100)
.background(.gray10)
.cornerRadius(18)

Button {
Task {
await viewModel.sendMessage(content: text)
text = ""
}
} label: {
Image("sendIcon")
}
}
.padding(.horizontal, 10)
.padding(.bottom, 10)
}
.frame(height: 100)
.background(Color.clear)
}
}

final class KeyboardHandler: ObservableObject {
@Published private(set) var keyboardHeight: CGFloat = 0

private var cancellable: AnyCancellable?

private let keyboardWillShow = NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)
.compactMap { notification -> CGFloat? in
guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
return nil
}
return keyboardFrame.height
}

private let keyboardWillHide = NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in CGFloat.zero }

init() {
cancellable = Publishers.Merge(keyboardWillShow, keyboardWillHide)
.receive(on: DispatchQueue.main)
.sink { [weak self] height in
self?.keyboardHeight = min(height, UIScreen.main.bounds.height / 2)
}
}
}

0 comments on commit 7438b97

Please sign in to comment.