Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

코드 가독성 증가 (개발의 파인 다이닝 급인듯) & 카테고리 예외처리 & 기록소 이름 예외처리 #145

Merged
merged 23 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5727d72
refactor: 디렉토리 View와 ViewModel로 구분
Kyxxn Dec 4, 2024
deb0c66
fix: 기록소 닉네임 등록할 때, 10글자 제한
Kyxxn Dec 4, 2024
0e8b8cb
refactor: category CRUD 메소드 네이밍 변경
Kyxxn Dec 4, 2024
3586548
fix: Category의 MainActor 제거
Kyxxn Dec 4, 2024
9b5421d
refactor: 메소드 파라미터 네이밍 변경
Kyxxn Dec 4, 2024
80774ae
refactor: 카테고리 Output 네이밍 변경
Kyxxn Dec 4, 2024
ce65c6a
refactor: 파라미터 네이밍 변경
Kyxxn Dec 4, 2024
59fe418
fix: 카테고리 중복, 이름 길이, 빈 문자열 예외처리
Kyxxn Dec 4, 2024
1dc4d8f
feat: 카테고리 이름 예외처리에 따른 Alert 액션 수정
Kyxxn Dec 4, 2024
a120e4a
Merge branch 'develop' into fix/qa-home
Kyxxn Dec 4, 2024
ddad6bb
feat: audio 접근 없을 경우 dismiss 추가
Kyxxn Dec 4, 2024
3970fa1
fix: 오디오 접근권한 없을 경우 설정 Alert
Kyxxn Dec 4, 2024
6dde056
refactor: 디렉토리 구조 변경
Kyxxn Dec 4, 2024
cfd1bf6
feat: 키보드 높이만큼 오르락 내리락 메소드 구현
Kyxxn Dec 4, 2024
90fad63
fix: 중복 메소드 네이밍 변경
Kyxxn Dec 4, 2024
a456105
feat: 기록소 등록화면에서 키보드 오르락 내리락 뷰 움직이기 구현
Kyxxn Dec 4, 2024
91b5c01
refactor: 뷰모델의 Input에서 viewDidLoad 모두 제거
Kyxxn Dec 4, 2024
2707328
chore: 린트 수정
Kyxxn Dec 4, 2024
17a4dd4
fix: 비디오 안 올라가던 문제 해결
Kyxxn Dec 4, 2024
ced2faa
refactor: 에러 로그에 #function 추가
Kyxxn Dec 4, 2024
ace0be2
refactor: 카테고리 CUD 유효성 검증 로그 변경
Kyxxn Dec 4, 2024
9e37a32
chore: 린트 해결
Kyxxn Dec 4, 2024
4b4cb49
refactor: BookCoverViewController의 Input 케이스 네이밍 변경
Kyxxn Dec 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import MHFoundation
import MHPresentation

final class SceneDelegate: UIResponder, UIWindowSceneDelegate {

Check warning on line 8 in MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Type Body Length Violation: Type body should span 250 lines or less excluding comments and whitespace: currently spans 304 lines (type_body_length)

Check warning on line 8 in MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Type Body Length Violation: Type body should span 250 lines or less excluding comments and whitespace: currently spans 304 lines (type_body_length)
var window: UIWindow?

func scene(
Expand Down Expand Up @@ -73,11 +73,12 @@
try registerUseCaseDependency()
try registerViewModelFactoryDependency()
} catch let error as MHCoreError {
MHLogger.error("\(error.description)")
MHLogger.error(error.description + #function)
} catch {
MHLogger.error("\(error.localizedDescription)")
MHLogger.error(error.localizedDescription + #function)
}
}

private func registerStorageDepedency() throws {
DIContainer.shared.register(CoreDataStorage.self, object: CoreDataStorage())

Expand Down Expand Up @@ -141,7 +142,7 @@
)
}

private func registerUseCaseDependency() throws {

Check warning on line 145 in MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Function Body Length Violation: Function body should span 50 lines or less excluding comments and whitespace: currently spans 90 lines (function_body_length)

Check warning on line 145 in MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Function Body Length Violation: Function body should span 50 lines or less excluding comments and whitespace: currently spans 90 lines (function_body_length)
// MARK: MemorialHouse UseCase
let memorialHouseNameRepository = try DIContainer.shared.resolve(MemorialHouseNameRepository.self)
DIContainer.shared.register(
Expand Down Expand Up @@ -245,7 +246,7 @@
)
}

private func registerViewModelFactoryDependency() throws {

Check warning on line 249 in MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Function Body Length Violation: Function body should span 50 lines or less excluding comments and whitespace: currently spans 87 lines (function_body_length)

Check warning on line 249 in MemorialHouse/MHApplication/MHApplication/Source/App/SceneDelegate.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Function Body Length Violation: Function body should span 50 lines or less excluding comments and whitespace: currently spans 87 lines (function_body_length)
// MARK: Register ViewModel
let createMemorialHouseNameUseCase = try DIContainer.shared.resolve(CreateMemorialHouseNameUseCase.self)
DIContainer.shared.register(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ final class CreateAudioViewController: UIViewController {
configureAddSubviews()
configureConstraints()
configureAddActions()
input.send(.viewDidLoad)
input.send(.prepareTemporaryAudio)
}

// MARK: - Setup
Expand Down Expand Up @@ -274,19 +274,11 @@ final class CreateAudioViewController: UIViewController {

// MARK: - Helper
private func requestMicrophonePermission() {
let alert = UIAlertController(
title: "마이크 권한 필요",
message: "설정에서 마이크 권한을 허용해주세요.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .default) { [weak self] _ in
self?.dismiss(animated: true)
})
Task {
AVAudioSession.sharedInstance().requestRecordPermission { @Sendable granted in
Task { @MainActor in
if !granted {
self.present(alert, animated: true, completion: nil)
self.showRedirectSettingAlert(with: .audio)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import MHDomain
public final class CreateAudioViewModel: ViewModelType {
// MARK: - Type
enum Input {
case viewDidLoad
case prepareTemporaryAudio
case audioButtonTapped
case saveButtonTapped
case recordCancelled
Expand Down Expand Up @@ -39,8 +39,8 @@ public final class CreateAudioViewModel: ViewModelType {
func transform(input: AnyPublisher<Input, Never>) -> AnyPublisher<Output, Never> {
input.sink { [weak self] event in
switch event {
case .viewDidLoad:
Task { await self?.viewDidLoad() }
case .prepareTemporaryAudio:
Task { await self?.prepareTemporaryAudio() }
case .audioButtonTapped:
self?.audioButtonTapped()
case .saveButtonTapped:
Expand All @@ -54,14 +54,14 @@ public final class CreateAudioViewModel: ViewModelType {
}

// MARK: - Helper
private func viewDidLoad() async {
private func prepareTemporaryAudio() async {
let mediaDescription = MediaDescription(type: .audio)
self.mediaDescription = mediaDescription
do {
let url = try await temporaryStoreMediaUsecase.execute(media: mediaDescription)
output.send(.audioFileURL(url: url))
} catch {
MHLogger.error("Error in store audio file url: \(error.localizedDescription)")
MHLogger.error(error.localizedDescription + #function)
completion(nil)
output.send(.recordCompleted)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@ public struct CreateAudioViewModelFactory {
)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ final class BookViewController: UIViewController {
let editBookViewController = EditBookViewController(viewModel: editBookViewModel, mode: .modify)
navigationController?.pushViewController(editBookViewController, animated: true)
} catch {
MHLogger.error(error)
MHLogger.error(error.localizedDescription + #function)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ final class BookCoverViewController: UIViewController {
configureAddSubviews()
configureConstraints()
configureAction()
createInput.send(.viewDidAppear)
createInput.send(.setBookColor)
modifyInput.send(.loadBookCover)
}

Expand Down Expand Up @@ -233,7 +233,7 @@ final class BookCoverViewController: UIViewController {
let editBookViewController = EditBookViewController(viewModel: editBookViewModel)
navigationController?.pushViewController(editBookViewController, animated: true)
} catch {
MHLogger.error(error)
MHLogger.error(error.localizedDescription + #function)
}
}
}
Expand Down Expand Up @@ -489,7 +489,7 @@ extension BookCoverViewController: BookCategoryViewControllerDelegate {

self.present(navigationController, animated: true)
} catch {
MHLogger.error(error)
MHLogger.error(error.localizedDescription + #function)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Photos
// TODO: - 에러 처리 필요
final class CreateBookCoverViewModel: ViewModelType {
enum Input {
case viewDidAppear
case setBookColor
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: 해당 input은 북 컬러를 셋팅한다기보단 BookCover를 처음에 생성하고 첫 셋팅을 총괄하는 input이라 네이밍을 SetBookCover 정도로 하는게 좋을 것 같긴합니당 !

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

임정 합니다 수정했습니닷

case changedBookTitle(title: String?)
case changedBookColor(colorIndex: Int)
case changedBookImage(bookImage: Data?)
Expand Down Expand Up @@ -60,7 +60,7 @@ final class CreateBookCoverViewModel: ViewModelType {
func transform(input: AnyPublisher<Input, Never>) -> AnyPublisher<Output, Never> {
input.sink { [weak self] event in
switch event {
case .viewDidAppear:
case .setBookColor:
self?.setBookColor(nowIndex: 0)
Task { try await self?.fetchMemorialHouseName() }
case .changedBookTitle(let title):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ final class BookCategoryViewController: UIViewController {

setup()
bind()
input.send(.viewDidLoad)
input.send(.fetchCategories)
configureNavigationBar()
configureConstraints()
}
Expand All @@ -62,11 +62,13 @@ final class BookCategoryViewController: UIViewController {
private func bind() {
let output = viewModel.transform(input: input.eraseToAnyPublisher())

output.sink { [weak self] event in
output
.receive(on: DispatchQueue.main)
.sink { [weak self] event in
switch event {
case .createdCategory, .updatedCategory, .fetchCategories, .deletedCategory:
self?.categoryTableView.reloadData()
case .failed(let errorMessage):
case .failure(let errorMessage):
self?.showErrorAlert(with: errorMessage)
}
}.store(in: &cancellables)
Expand Down Expand Up @@ -112,24 +114,18 @@ final class BookCategoryViewController: UIViewController {
normal: normalAttributes,
selected: selectedAttributes
) { [weak self] in
guard let self else { return }

let alert = UIAlertController(
title: "카테고리 추가",
message: "새로운 카테고리를 입력해주세요.",
textFieldConfiguration: { textField in
textField.placeholder = "카테고리 이름"
},
confirmHandler: { [weak self] newText in
guard let newText, !newText.isEmpty else {
MHLogger.error("입력한 카테고리 이름이 유효하지 않습니다.")
return
}
self?.input.send(.addCategory(text: newText))
self?.input.send(.createCategory(text: newText ?? ""))
}
)

self.present(alert, animated: true)
self?.present(alert, animated: true)
}
}

Expand Down Expand Up @@ -171,26 +167,20 @@ extension BookCategoryViewController: UITableViewDelegate {
style: .normal,
title: "수정"
) { [weak self] _, _, completion in
guard let self else { return }
let alert = UIAlertController(
title: "카테고리 수정",
message: "수정할 카테고리 이름을 입력해주세요.",
textFieldConfiguration: { textField in
textField.placeholder = "카테고리 이름"
textField.text = self.viewModel.categories[indexPath.row].name
textField.text = self?.viewModel.categories[indexPath.row].name
},
confirmHandler: { [weak self] newText in
guard let self, let newText = newText, !newText.isEmpty else {
MHLogger.error("수정할 카테고리 이름이 유효하지 않습니다.")
completion(false)
return
}
self.input.send(.updateCategory(index: indexPath.row, text: newText))
self?.input.send(.updateCategory(index: indexPath.row, text: newText ?? ""))
completion(true)
}
)

self.present(alert, animated: true)
self?.present(alert, animated: true)
}

let deleteAction = UIContextualAction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import MHCore

final class BookCategoryViewModel: ViewModelType {
enum Input {
case viewDidLoad
case addCategory(text: String)
case createCategory(text: String)
case fetchCategories
case updateCategory(index: Int, text: String)
case deleteCategory(index: Int)
}
Expand All @@ -15,7 +15,7 @@ final class BookCategoryViewModel: ViewModelType {
case fetchCategories
case updatedCategory
case deletedCategory
case failed(String)
case failure(String)
}

private let createBookCategoryUseCase: CreateBookCategoryUseCase
Expand Down Expand Up @@ -52,12 +52,12 @@ final class BookCategoryViewModel: ViewModelType {
input.sink { [weak self] event in
Task {
switch event {
case .viewDidLoad:
case .createCategory(let name):
await self?.createCategory(name: name)
case .fetchCategories:
await self?.fetchCategories()
case .addCategory(let text):
await self?.createCategory(text: text)
case .updateCategory(let index, let text):
await self?.updateCategory(index: index, text: text)
await self?.updateCategory(index: index, name: text)
case .deleteCategory(let index):
await self?.deleteCategory(index: index)
}
Expand All @@ -67,57 +67,59 @@ final class BookCategoryViewModel: ViewModelType {
return output.eraseToAnyPublisher()
}

// FIXME: MainActor 제거
@MainActor
private func createCategory(text: String) async {
private func createCategory(name: String) async {
guard validateCategoryName(with: name) else {
MHLogger.error("카테고리 생성 유효성 검증 실패: \(name)" + #function)
output.send(.failure("카테고리 생성 유효성 검증 실패"))
return
}

do {
let category = BookCategory(order: categories.count, name: text)
let category = BookCategory(order: categories.count, name: name)
try await createBookCategoryUseCase.execute(with: category)
categories.append(category)
output.send(.createdCategory)
} catch {
MHLogger.error("카테고리를 생성하는데 실패했습니다: \(error)")
output.send(.failed("카테고리를 생성하는데 실패했습니다"))
MHLogger.error("카테고리를 생성하는데 실패했습니다: \(error)" + #function)
output.send(.failure("카테고리를 생성하는데 실패했습니다"))
}
}

@MainActor
private func fetchCategories() async {
do {
let fetchedCategories = try await fetchBookCategoriesUseCase.execute()
categories.append(contentsOf: fetchedCategories)
output.send(.fetchCategories)
} catch {
MHLogger.error("카테고리를 불러오는데 실패했습니다: \(error)")
output.send(.failed("카테고리를 불러오는데 실패했습니다"))
MHLogger.error("카테고리를 불러오는데 실패했습니다: \(error)" + #function)
output.send(.failure("카테고리를 불러오는데 실패했습니다"))
}
}

@MainActor
private func updateCategory(index: Int, text: String) async {
guard index >= 0 && index < categories.count else {
MHLogger.error("유효하지 않은 인덱스: \(index)")
output.send(.failed("유효하지 않은 인덱스: \(index)"))
private func updateCategory(index: Int, name: String) async {
guard validateIndex(index),
validateCategoryName(with: name) else {
MHLogger.error("카테고리 업데이트 유효성 검증 실패: \(name)" + #function)
output.send(.failure("카테고리 업데이트 유효성 검증 실패"))
return
}

do {
let oldName = categories[index].name
let category = BookCategory(order: index, name: text)
let category = BookCategory(order: index, name: name)
try await updateBookCategoryUseCase.execute(oldName: oldName, with: category)
categories[index] = category
output.send(.updatedCategory)
} catch {
MHLogger.error("카테고리를 업데이트하는데 실패했습니다: \(error)")
output.send(.failed("카테고리를 업데이트하는데 실패했습니다"))
MHLogger.error("카테고리를 업데이트하는데 실패했습니다: \(error)" + #function)
output.send(.failure("카테고리를 업데이트하는데 실패했습니다"))
}
}

@MainActor
private func deleteCategory(index: Int) async {
guard index >= 0 && index < categories.count else {
MHLogger.error("유효하지 않은 인덱스: \(index)")
output.send(.failed("유효하지 않은 인덱스: \(index)"))
guard validateIndex(index) else {
MHLogger.error("카테고리 삭제 유효성 검증 실패: \(index)" + #function)
output.send(.failure("카테고리를 삭제하는데 실패했습니다"))
return
}

Expand All @@ -127,8 +129,55 @@ final class BookCategoryViewModel: ViewModelType {
categories.remove(at: index)
output.send(.deletedCategory)
} catch {
MHLogger.error("카테고리를 삭제하는데 실패했습니다: \(error)")
output.send(.failed("카테고리를 삭제하는데 실패했습니다"))
MHLogger.error("카테고리를 삭제하는데 실패했습니다: \(error)" + #function)
output.send(.failure("카테고리를 삭제하는데 실패했습니다"))
}
}

// MARK: - 카테고리 유효성 검사
private func validateCategoryName(with name: String) -> Bool {
return validateNonEmptyName(name)
&& validateUniqueName(name)
&& validateNameLength(name)
}

// 인덱스 유효성 검사
private func validateIndex(_ index: Int) -> Bool {
guard index >= 0 && index < categories.count else {
MHLogger.error("유효하지 않은 인덱스: \(index)" + #function)
output.send(.failure("유효하지 않은 인덱스: \(index)"))
return false
}
return true
}

// 공백 또는 빈 문자열 검사
private func validateNonEmptyName(_ name: String) -> Bool {
guard !name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
MHLogger.error("카테고리 이름이 비어있거나 공백만 포함되어 있음: \(name)" + #function)
output.send(.failure("카테고리 이름은 공백일 수 없습니다."))
return false
}
return true
}

// 중복 이름 검사
private func validateUniqueName(_ name: String) -> Bool {
guard !categories.contains(where: { $0.name == name }) else {
MHLogger.error("중복된 카테고리 이름: \(name)" + #function)
output.send(.failure("이미 존재하는 카테고리: \(name)"))
return false
}
return true
}

// 이름 길이 검사
private func validateNameLength(_ name: String) -> Bool {
guard name.count <= 10 else {
MHLogger.error("카테고리 이름이 너무 깁니다: \(name)" + #function)
output.send(.failure("카테고리 이름은 10자 이하여야 합니다."))
return false
}
return true
}
}
Loading
Loading