Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 19 additions & 31 deletions Projects/Chat/Chat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objectVersion = 56;
objects = {

/* Begin PBXBuildFile section */
Expand All @@ -12,6 +12,9 @@
7F3F4DE30EE902DEABC6040E /* ChatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AAFFC509053CC99EAA3B277 /* ChatViewModel.swift */; };
9179FB9B1C2AEDCB7A3CFC7E /* ChatCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 588CFD307FD55B64676DA657 /* ChatCoordinator.swift */; };
91C973D65FBDD1ABF65A1A2A /* Domain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F910F30DEBC80ABF5CC5A6F9 /* Domain.framework */; };
9516ED482E7076F800F548A1 /* ChatAnalysisViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9516ED472E7076E900F548A1 /* ChatAnalysisViewController.swift */; };
9516ED4F2E708CE100F548A1 /* ChatMainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9516ED4E2E708CD900F548A1 /* ChatMainViewController.swift */; };
956C4D722E7690C600E32F93 /* ChatDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 956C4D712E7690BF00E32F93 /* ChatDetailViewController.swift */; };
B6F14AC32696F30284073B2F /* Chat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EEE28C25EAD3F5DC9E76FFAC /* Chat.framework */; };
B89B886F288E5BDECC82BA50 /* Common.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 64BD6CA2A2FDA5A5D9C4A87D /* Common.framework */; };
E096380D552BAA6326ED8397 /* CommonUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CB61D7206C15B58E35E2DEB /* CommonUI.framework */; };
Expand Down Expand Up @@ -60,6 +63,9 @@
5AAFFC509053CC99EAA3B277 /* ChatViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatViewModel.swift; sourceTree = "<group>"; };
5E359E9093579B130E0EDD53 /* Then.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Then.framework; sourceTree = BUILT_PRODUCTS_DIR; };
64BD6CA2A2FDA5A5D9C4A87D /* Common.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Common.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9516ED472E7076E900F548A1 /* ChatAnalysisViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatAnalysisViewController.swift; sourceTree = "<group>"; };
9516ED4E2E708CD900F548A1 /* ChatMainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatMainViewController.swift; sourceTree = "<group>"; };
956C4D712E7690BF00E32F93 /* ChatDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatDetailViewController.swift; sourceTree = "<group>"; };
BC90A71D97E9F538AACFD586 /* SnapKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SnapKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C8A6CF81DAC793585959F31D /* Chat-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Chat-Info.plist"; sourceTree = "<group>"; };
E05B48A08FE1A700DE3FEE63 /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -154,7 +160,10 @@
B076E5D7F9914D43D18020A7 /* View */ = {
isa = PBXGroup;
children = (
9516ED4E2E708CD900F548A1 /* ChatMainViewController.swift */,
E083003E4769EA2B259F4BE8 /* ChatViewController.swift */,
9516ED472E7076E900F548A1 /* ChatAnalysisViewController.swift */,
956C4D712E7690BF00E32F93 /* ChatDetailViewController.swift */,
);
path = View;
sourceTree = "<group>";
Expand Down Expand Up @@ -227,8 +236,6 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
TargetAttributes = {
};
};
buildConfigurationList = 5BF2D8A0F20A5563CE9A6AEB /* Build configuration list for PBXProject "Chat" */;
compatibilityVersion = "Xcode 14.0";
Expand Down Expand Up @@ -278,9 +285,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9516ED4F2E708CE100F548A1 /* ChatMainViewController.swift in Sources */,
9179FB9B1C2AEDCB7A3CFC7E /* ChatCoordinator.swift in Sources */,
11E1631C9C29E4197C2782CB /* ChatViewController.swift in Sources */,
7F3F4DE30EE902DEABC6040E /* ChatViewModel.swift in Sources */,
9516ED482E7076F800F548A1 /* ChatAnalysisViewController.swift in Sources */,
956C4D722E7690C600E32F93 /* ChatDetailViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -314,21 +324,14 @@
"$(inherited)",
"-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap",
);
OTHER_SWIFT_FLAGS = (
"$(inherited)",
"-Xcc",
"-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap",
);
OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = io.tuist.ChatTests;
PRODUCT_NAME = ChatTests;
SDKROOT = iphoneos;
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
"$(inherited)",
DEBUG,
);
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
SWIFT_COMPILATION_MODE = singlefile;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
Expand Down Expand Up @@ -413,11 +416,7 @@
"$(inherited)",
"-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap",
);
OTHER_SWIFT_FLAGS = (
"$(inherited)",
"-Xcc",
"-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap",
);
OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = io.tuist.Chat;
PRODUCT_NAME = Chat;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -511,11 +510,7 @@
"$(inherited)",
"-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap",
);
OTHER_SWIFT_FLAGS = (
"$(inherited)",
"-Xcc",
"-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap",
);
OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = io.tuist.ChatTests;
PRODUCT_NAME = ChatTests;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -553,22 +548,15 @@
"$(inherited)",
"-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap",
);
OTHER_SWIFT_FLAGS = (
"$(inherited)",
"-Xcc",
"-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap",
);
OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = io.tuist.Chat;
PRODUCT_NAME = Chat;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
"$(inherited)",
DEBUG,
);
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
SWIFT_COMPILATION_MODE = singlefile;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
Expand Down
101 changes: 101 additions & 0 deletions Projects/Chat/Sources/View/ChatAnalysisViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//
// ChatAnalysisViewController.swift
// Chat
//
// Created by 박지윤 on 9/9/25.
//

import UIKit
import CommonUI
import Domain
import RxSwift

public class ChatAnalysisViewController: BaseViewController {
let viewModel: ChatViewModel
private let chatAnalysisView = ChatAnalysisView()
let navigationBar = DefaultNavigationBar(leftImage: nil,
rightImage: CommonUIAssets.IconClose ?? nil,
title: "")

private var chatDetail: ChatDetailVO

public init(chatViewModel: ChatViewModel, chatDetail: ChatDetailVO) {
self.viewModel = chatViewModel
self.chatDetail = chatDetail
super.init()
}

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

public override func viewDidLoad() {
super.viewDidLoad()
navigationBar.setupViewProperty(title: chatDetail.chatRoom.title)
chatAnalysisView.setupAnalysisData(chatDetail.chatList)
setupActions()
}

public override func setupViewProperty() {
view.backgroundColor = CommonUIAssets.LMOrange4
}

public override func setupHierarchy() {
[navigationBar, chatAnalysisView]
.forEach { view.addSubview($0) }
}

public override func setupLayout() {
navigationBar.snp.makeConstraints {
$0.top.equalTo(view.safeAreaLayoutGuide)
$0.width.centerX.equalToSuperview()
}

chatAnalysisView.snp.makeConstraints {
$0.top.equalTo(navigationBar.snp.bottom)
$0.horizontalEdges.bottom.equalToSuperview()
}
}

private func setupActions() {
// DefaultNavigationBar의 기본 타겟 제거 후 우리의 커스텀 액션 추가
navigationBar.rightButton.removeTarget(navigationBar, action: #selector(DefaultNavigationBar.rightButtonTapped), for: .touchUpInside)
navigationBar.rightButton.addTarget(self, action: #selector(handleRightButtonTapped), for: .touchUpInside)

// SaveButton 액션 설정
chatAnalysisView.onSaveButtonTapped.subscribe(onNext: { [weak self] in
self?.handleSaveButtonTapped()
}).disposed(by: disposeBag)
}

@objc private func handleRightButtonTapped() {
showExitConfirmationAlert()
}

private func handleSaveButtonTapped() {
// 저장 버튼 클릭 시 루트 뷰컨트롤러로 이동
navigationController?.popToRootViewController(animated: true)
}

private func showExitConfirmationAlert() {
let lmAlert = LMAlert(title: "저장하지 않은 대화는 사라집니다.\n그래도 나가시겠습니까?")

lmAlert.setCancelAction {
// 아니요 버튼 - 아무것도 하지 않음
}

lmAlert.setConfirmAction { [weak self] in
self?.deleteChatAndExit()
}

lmAlert.show(in: view)
}

private func deleteChatAndExit() {
// 대화방 삭제 API 호출
viewModel.deleteChat()

// 루트 뷰컨트롤러로 이동
navigationController?.popToRootViewController(animated: true)
}
}
90 changes: 90 additions & 0 deletions Projects/Chat/Sources/View/ChatDetailViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//
// ChatDetailViewController.swift
// Chat
//
// Created by 박지윤 on 1/1/25.
//

import UIKit
import CommonUI
import Domain
import RxSwift

public class ChatDetailViewController: BaseViewController {

let viewModel: ChatViewModel
private let chatDetailView = ChatDetailView()
let navigationBar = DefaultNavigationBar(leftImage: CommonUIAssets.IconBack ?? nil,
rightImage: nil,
title: "")

private var chatRoom: ChatRoomVO
private var chatDetail: ChatDetailVO?

public init(chatViewModel: ChatViewModel, chatRoom: ChatRoomVO) {
self.viewModel = chatViewModel
self.chatRoom = chatRoom
super.init()
}

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

public override func viewDidLoad() {
super.viewDidLoad()
navigationBar.setupViewProperty(title: chatRoom.title)
setupActions()
bindData()
loadChatDetail()
}

public override func setupViewProperty() {
view.backgroundColor = CommonUIAssets.LMOrange4
}

public override func setupHierarchy() {
[navigationBar, chatDetailView]
.forEach { view.addSubview($0) }
}

public override func setupLayout() {
navigationBar.snp.makeConstraints {
$0.top.equalTo(view.safeAreaLayoutGuide)
$0.width.centerX.equalToSuperview()
}

chatDetailView.snp.makeConstraints {
$0.top.equalTo(navigationBar.snp.bottom)
$0.horizontalEdges.bottom.equalToSuperview()
}
}

private func setupActions() {
// LeftButton 액션 (뒤로 가기)
// navigationBar.leftButton.removeTarget(navigationBar, action: #selector(DefaultNavigationBar.leftButtonTapped), for: .touchUpInside)
// navigationBar.leftButton.addTarget(self, action: #selector(handleBackButtonTapped), for: .touchUpInside)
}

private func bindData() {
viewModel.chatDetailSubject
.observe(on: MainScheduler.instance)
.subscribe(onNext: { [weak self] (chatDetail: ChatDetailVO) in
self?.updateChatDetail(chatDetail)
})
.disposed(by: disposeBag)
}

private func loadChatDetail() {
viewModel.getChatDetail(chatRoomId: chatRoom.chatRoomId)
}

@objc private func handleBackButtonTapped() {
navigationController?.popViewController(animated: true)
}

public func updateChatDetail(_ chatDetail: ChatDetailVO) {
self.chatDetail = chatDetail
chatDetailView.setupDetailData(chatDetail.chatList)
}
}
Loading
Loading