From cca1c510cd60be07c3e8f6c3a01755a1938fa52b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Wed, 11 Jun 2025 21:30:54 +0900 Subject: [PATCH 01/13] =?UTF-8?q?[#189]=20LibraryUseCase=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EC=95=88=EC=93=B0=EB=8A=94=20Repo=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- B.READ/B.READ/Sources/App/DIContainer/DIContainer.swift | 1 - .../Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift | 5 ----- B.READ/UsecaseTest/LibraryUseCaseTest.swift | 3 --- 3 files changed, 9 deletions(-) diff --git a/B.READ/B.READ/Sources/App/DIContainer/DIContainer.swift b/B.READ/B.READ/Sources/App/DIContainer/DIContainer.swift index 80c1f12c..b313dea1 100644 --- a/B.READ/B.READ/Sources/App/DIContainer/DIContainer.swift +++ b/B.READ/B.READ/Sources/App/DIContainer/DIContainer.swift @@ -64,7 +64,6 @@ extension DIContainer { userInfoRepository: userInfoRepository, bookRepository: bookRepository, recordRepository: recordRepository, - quoteRepository: quoteRepository, bookService: AladinService() ), for: LibraryUseCase.self diff --git a/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift b/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift index 8a70f1a4..984d01af 100644 --- a/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift +++ b/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift @@ -12,22 +12,17 @@ final class LibraryUseCaseImpl: LibraryUseCase { private let userInfoRepository: UserInfoRepository private let bookRepository: BookRepository private let recordRepository: RecordRepository - // private let memoRepository: MemoRepository - private let quoteRepository: QuoteRepository - // private let noteRepository: NoteRepository private let bookService: BookService init( userInfoRepository: UserInfoRepository, bookRepository: BookRepository, recordRepository: RecordRepository, - quoteRepository: QuoteRepository, bookService: BookService ) { self.userInfoRepository = userInfoRepository self.bookRepository = bookRepository self.recordRepository = recordRepository - self.quoteRepository = quoteRepository self.bookService = bookService } diff --git a/B.READ/UsecaseTest/LibraryUseCaseTest.swift b/B.READ/UsecaseTest/LibraryUseCaseTest.swift index efa2f3a9..3deaa428 100644 --- a/B.READ/UsecaseTest/LibraryUseCaseTest.swift +++ b/B.READ/UsecaseTest/LibraryUseCaseTest.swift @@ -17,7 +17,6 @@ struct LibraryUseCaseTest { private let userInfoRepository: UserInfoRepository private let recordRepository: RecordRepository private let bookRepository: BookRepository - private let quoteRepository: QuoteRepository private let bookService: BookService init() { @@ -26,14 +25,12 @@ struct LibraryUseCaseTest { userInfoRepository = UserInfoRepositoryImpl(modelContainer: storage.modelContainer) recordRepository = RecordRepositoryImpl(modelContainer: storage.modelContainer) bookRepository = BookRepositoryImpl(modelContainer: storage.modelContainer) - quoteRepository = QuoteRepositoryImpl(modelContainer: storage.modelContainer) bookService = AladinService(client: MockNetworkClient(nextMockFileName: "SearchList")) libraryUseCase = LibraryUseCaseImpl( userInfoRepository: userInfoRepository, bookRepository: bookRepository, recordRepository: recordRepository, - quoteRepository: quoteRepository, bookService: bookService ) } From 75c51752ba314daabd94dbafdbd04649bb302787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Wed, 11 Jun 2025 21:36:38 +0900 Subject: [PATCH 02/13] =?UTF-8?q?[#189]=20LibraryUseCase=EC=97=90=EC=84=9C?= =?UTF-8?q?=20loadRecordList=20Task=20=EC=BA=94=EC=8A=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift b/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift index 984d01af..9f3fa589 100644 --- a/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift +++ b/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift @@ -92,12 +92,13 @@ final class LibraryUseCaseImpl: LibraryUseCase { // 3. record 기준으로 각각의 책정보 가져오는 걸 자식 태스크로 지정 group.addTask { do { + try Task.checkCancellation() let book = try await self.bookRepository.fetchBook(isbn: record.isbn) return (record, book) - } catch { - // TODO: - RepositoryError.dataNotFound이면 알라딘에서 책검색, 아니면 nil - print(error.localizedDescription) - return nil + + } catch RepositoryError.dataNotFound { + let book = try await self.requestBookDetail(isbn: record.isbn) + return (record, book) } } } From 89599e4c3034688d89fe44d459ff326435bfed76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Wed, 11 Jun 2025 21:46:06 +0900 Subject: [PATCH 03/13] =?UTF-8?q?[#189]=20RecordDetailViewModel=20?= =?UTF-8?q?=ED=83=9C=EC=8A=A4=ED=81=AC=EC=B7=A8=EC=86=8C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewModel/RecordDetailViewModel.swift | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/B.READ/B.READ/Sources/Presentation/Library/ViewModel/RecordDetailViewModel.swift b/B.READ/B.READ/Sources/Presentation/Library/ViewModel/RecordDetailViewModel.swift index b9e60f22..039187c5 100644 --- a/B.READ/B.READ/Sources/Presentation/Library/ViewModel/RecordDetailViewModel.swift +++ b/B.READ/B.READ/Sources/Presentation/Library/ViewModel/RecordDetailViewModel.swift @@ -25,6 +25,7 @@ final class RecordDetailViewModel: ObservableObject { var selectedQuote: QuoteVO? = nil var selectedMemo: MemoVO? = nil var summary: SummaryVO? = nil + private var currentTask: Task? = nil init(recordID: String) { self.recordID = recordID @@ -74,10 +75,11 @@ private extension RecordDetailViewModel { /// 독서 기록 조회에서 필요한 정보를 불러옴 func loadInfo(id: String) { - Task { [weak self] in - guard let self = self else { return } + currentTask?.cancel() + + currentTask = Task { + try? Task.checkCancellation() - // TODO: - [시르] VO 생성은 전부 비동기 그룹처리 do { // 1. 독서 기록 정보를 불러옴 let info: (record: Record, book: Book) = try await libraryUseCase.loadRecord(id) @@ -118,9 +120,7 @@ private extension RecordDetailViewModel { /// 즐겨 찾기 정보를 업데이트 func toggleIsFavorite() { - Task { [weak self] in - guard let self = self else { return } - + Task { // 1. 즐겨 찾기 정보를 토글 await MainActor.run { self.record?.isFavorite.toggle() @@ -146,9 +146,7 @@ private extension RecordDetailViewModel { /// 독서 기록을 삭제 func deleteRecord() { - Task { [weak self] in - guard let self = self else { return } - + Task { // 1. 현재 레코드 정보 확인 guard let record = self.record else { print("ViewModel Error: Record Not Found") @@ -195,9 +193,7 @@ private extension RecordDetailViewModel { /// 문장 정렬 func sortQuotes() async { - Task { [weak self] in - guard let self = self else { return } - + Task { let by = self.selectedSort[1] // 1. 정렬한 결과 let sortQuotes: [QuoteVO] = quotes.sorted(by: by.sort) From a6a3e105ba7380bb8f310901dfb2a3b27bf6cfa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Wed, 11 Jun 2025 21:53:34 +0900 Subject: [PATCH 04/13] =?UTF-8?q?[#189]=20LibraryViewModel=20Task=EC=BA=94?= =?UTF-8?q?=EC=8A=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Library/ViewModel/LibraryViewModel.swift | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/B.READ/B.READ/Sources/Presentation/Library/ViewModel/LibraryViewModel.swift b/B.READ/B.READ/Sources/Presentation/Library/ViewModel/LibraryViewModel.swift index a7400dfe..d560dcb1 100644 --- a/B.READ/B.READ/Sources/Presentation/Library/ViewModel/LibraryViewModel.swift +++ b/B.READ/B.READ/Sources/Presentation/Library/ViewModel/LibraryViewModel.swift @@ -36,6 +36,7 @@ final class LibraryViewModel: ObservableObject { // DB에서 가져온 전체 독서기록 private var records: [RecordCellVO] = [] private var filteredRecords: [RecordCellVO] = [] + private var currentTask: Task? = nil // MARK: - Dependency @Dependency @@ -69,8 +70,13 @@ private extension LibraryViewModel { // 독서 기록을 불러옴 func loadRecords() { viewState = .loading - Task { + + currentTask?.cancel() + + currentTask = Task { + try? Task.checkCancellation() await fetchRecords() + await withTaskGroup(of: Void.self) { group in group.addTask { // 2. 불러온 독서 기록의 상태별 개수 확인 @@ -84,6 +90,7 @@ private extension LibraryViewModel { await self.sortDisplayRecords(by: self.selectedSort[self.selectedTab]) } } + await MainActor.run { viewState = .loaded } @@ -92,17 +99,23 @@ private extension LibraryViewModel { // 상단 탭바를 선택 func selectTab() { - Task { + currentTask?.cancel() + + currentTask = Task { + try? Task.checkCancellation() // 1. 선택된 탭을 기준으로 필터 적용 await self.filterRecords() // 2. 필터 적용된 독서 기록에 정렬 적용 await self.sortDisplayRecords(by: self.selectedSort[self.selectedTab]) } } - + // 정렬을 선택 func selectSort() { - Task { + currentTask?.cancel() + + currentTask = Task { + try? Task.checkCancellation() await self.sortDisplayRecords(by: self.selectedSort[self.selectedTab]) } } From 8bb6cb879302be7935641bc1c0ce84010d94c2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Wed, 11 Jun 2025 22:17:38 +0900 Subject: [PATCH 05/13] =?UTF-8?q?[#189]=20=EA=B8=B0=EB=A1=9D=EB=A9=94?= =?UTF-8?q?=EB=AA=A8,=20=EA=B8=B0=EB=A1=9D=EB=AC=B8=EC=9E=A5=20=EB=B7=B0?= =?UTF-8?q?=EB=AA=A8=EB=8D=B8=20Task=20=EC=BA=94=EC=8A=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Record/ViewModel/RecordMemoViewModel.swift | 7 ++++++- .../Record/ViewModel/RecordQuoteViewModel.swift | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/B.READ/B.READ/Sources/Presentation/Record/ViewModel/RecordMemoViewModel.swift b/B.READ/B.READ/Sources/Presentation/Record/ViewModel/RecordMemoViewModel.swift index c590e5d4..15ad41fb 100644 --- a/B.READ/B.READ/Sources/Presentation/Record/ViewModel/RecordMemoViewModel.swift +++ b/B.READ/B.READ/Sources/Presentation/Record/ViewModel/RecordMemoViewModel.swift @@ -19,6 +19,7 @@ final class RecordMemoViewModel: ObservableObject { // MARK: - Internal Variable private(set) var memoGroups: [MemoGroup] = [] var selectedMemo: MemoVO? = nil + private var currentTask: Task? = nil // MARK: - Dependency @Dependency private var memoUseCase: MemoUseCase @@ -52,7 +53,11 @@ final class RecordMemoViewModel: ObservableObject { private extension RecordMemoViewModel { /// 메모를 불러와서 뷰에 보여줄 형태로 가공합니다. func loadMemoGroups() { - Task { + currentTask?.cancel() + + currentTask = Task { + try? Task.checkCancellation() + do { // 1. 전체 독서 기록을 받아옴 let allRecords = try await libraryUseCase.loadRecordList() diff --git a/B.READ/B.READ/Sources/Presentation/Record/ViewModel/RecordQuoteViewModel.swift b/B.READ/B.READ/Sources/Presentation/Record/ViewModel/RecordQuoteViewModel.swift index ef54ce6f..fd583ce7 100644 --- a/B.READ/B.READ/Sources/Presentation/Record/ViewModel/RecordQuoteViewModel.swift +++ b/B.READ/B.READ/Sources/Presentation/Record/ViewModel/RecordQuoteViewModel.swift @@ -19,6 +19,7 @@ final class RecordQuoteViewModel: ObservableObject { // MARK: - Internal Variable private(set) var quoteGroups: [QuoteGroup] = [] var selectedQuote: QuoteVO? = nil + private var currentTask: Task? = nil // MARK: - Dependency @Dependency private var quoteUseCase: QuoteUseCase @@ -53,7 +54,11 @@ final class RecordQuoteViewModel: ObservableObject { private extension RecordQuoteViewModel { /// 문장을 불러와서 뷰에 보여줄 형태로 가공합니다. func loadQuoteGroups() { - Task { + currentTask?.cancel() + + currentTask = Task { + try? Task.checkCancellation() + do { // 1. 전체 독서 기록을 받아옴 let allRecords = try await libraryUseCase.loadRecordList() From 3b23ae2312b2a4e8b16ff0f3dee7c675e86520ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Wed, 11 Jun 2025 22:50:31 +0900 Subject: [PATCH 06/13] =?UTF-8?q?[#189]=20=20=EC=B1=85=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20=ED=8C=A8=EC=B9=98=ED=95=A0=EB=95=8C=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EA=B0=80=20=EC=97=86=EC=9C=BC=EB=A9=B4=20=EC=95=8C?= =?UTF-8?q?=EB=9D=BC=EB=94=98=EC=97=90=EC=84=9C=20=EB=B0=9B=EC=95=84?= =?UTF-8?q?=EC=99=80=EC=84=9C=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/App/DIContainer/DIContainer.swift | 7 +++- .../Domain/UseCaseImpl/MemoUseCaseImpl.swift | 35 +++++++++++++++++- .../Domain/UseCaseImpl/QuoteUseCaseImpl.swift | 37 +++++++++++++++++-- 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/B.READ/B.READ/Sources/App/DIContainer/DIContainer.swift b/B.READ/B.READ/Sources/App/DIContainer/DIContainer.swift index b313dea1..a3920551 100644 --- a/B.READ/B.READ/Sources/App/DIContainer/DIContainer.swift +++ b/B.READ/B.READ/Sources/App/DIContainer/DIContainer.swift @@ -75,7 +75,8 @@ extension DIContainer { userInfoRepository: userInfoRepository, bookRepository: bookRepository, memoRepository: memoRepository, - aiService: AlanService() + aiService: AlanService(), + bookService: AladinService() ), for: MemoUseCase.self ) @@ -85,7 +86,9 @@ extension DIContainer { QuoteUseCaseImpl( userInfoRepository: userInfoRepository, quoteRepository: quoteRepository, - bookRepository: bookRepository), + bookRepository: bookRepository, + bookService: AladinService() + ), for: QuoteUseCase.self ) diff --git a/B.READ/B.READ/Sources/Domain/UseCaseImpl/MemoUseCaseImpl.swift b/B.READ/B.READ/Sources/Domain/UseCaseImpl/MemoUseCaseImpl.swift index d6535bd1..4d34c8d2 100644 --- a/B.READ/B.READ/Sources/Domain/UseCaseImpl/MemoUseCaseImpl.swift +++ b/B.READ/B.READ/Sources/Domain/UseCaseImpl/MemoUseCaseImpl.swift @@ -13,17 +13,20 @@ final class MemoUseCaseImpl: MemoUseCase { let bookRepository: BookRepository let memoRepository: MemoRepository let aiService: AIService + private let bookService: BookService init( userInfoRepository: UserInfoRepository, bookRepository: BookRepository, memoRepository: MemoRepository, - aiService: AIService + aiService: AIService, + bookService: BookService ) { self.userInfoRepository = userInfoRepository self.bookRepository = bookRepository self.memoRepository = memoRepository self.aiService = aiService + self.bookService = bookService } func saveMemo(_ memo: Memo, in record: Record) async throws { @@ -89,7 +92,35 @@ final class MemoUseCaseImpl: MemoUseCase { } func loadBookTitle(_ isbn: String) async throws -> String { - return try await bookRepository.fetchBook(isbn: isbn).name + do { + return try await bookRepository.fetchBook(isbn: isbn).name + } catch { + // 도서 정보가 없다면 알라딘에서 검색 후 정보 생성하고 도서제목을 반환 + // 1. 알라딘에서 정보를 패치 + let bookDetail = try await bookService.fetchBookDetail(isbn: isbn) + + // 2. 패치한 정보로 엔티티 생성 + var book = Book( + isbn: bookDetail.isbn, + coverImage: nil, + name: bookDetail.title, + author: bookDetail.author, + publisher: bookDetail.publisher, + publishedAt: bookDetail.publishedDate.toDate() ?? .now, + totalPages: bookDetail.pageCount + ) + + // 3. 표지정보 업데이트 + if let url = URL(string: bookDetail.coverURL) { + let data = try? Data(contentsOf: url) + book.coverImage = data + } + + // 4. 책정보 생성 + try? await bookRepository.createBook(book) + // 5. 책 생성에 실패하든 성공하든 새로운 책제목을 반환 + return book.name + } } } diff --git a/B.READ/B.READ/Sources/Domain/UseCaseImpl/QuoteUseCaseImpl.swift b/B.READ/B.READ/Sources/Domain/UseCaseImpl/QuoteUseCaseImpl.swift index a9e2f2d6..9ab1dfb2 100644 --- a/B.READ/B.READ/Sources/Domain/UseCaseImpl/QuoteUseCaseImpl.swift +++ b/B.READ/B.READ/Sources/Domain/UseCaseImpl/QuoteUseCaseImpl.swift @@ -12,6 +12,7 @@ final class QuoteUseCaseImpl: QuoteUseCase { private let userInfoRepository: UserInfoRepository private let quoteRepository: QuoteRepository private let bookRepository: BookRepository + private let bookService: BookService /// 생성자 /// - Parameters: @@ -20,11 +21,13 @@ final class QuoteUseCaseImpl: QuoteUseCase { init( userInfoRepository: UserInfoRepository, quoteRepository: QuoteRepository, - bookRepository: BookRepository + bookRepository: BookRepository, + bookService: BookService ) { self.userInfoRepository = userInfoRepository self.quoteRepository = quoteRepository self.bookRepository = bookRepository + self.bookService = bookService } func saveQuote(_ quote: Quote, in record: Record) async throws { @@ -53,10 +56,36 @@ final class QuoteUseCaseImpl: QuoteUseCase { return try await quoteRepository.fetchAllQuotes() } - - // TODO: - 조회한 도서가 없을 경우 알라딘 검색 후 도서 저장 -> 도서 제목 반환 func loadBookTitle(_ isbn: String) async throws -> String { - return try await bookRepository.fetchBook(isbn: isbn).name + do { + return try await bookRepository.fetchBook(isbn: isbn).name + } catch RepositoryError.dataNotFound { + // 도서 정보가 없다면 알라딘에서 검색 후 정보 생성하고 도서제목을 반환 + // 1. 알라딘에서 정보를 패치 + let bookDetail = try await bookService.fetchBookDetail(isbn: isbn) + + // 2. 패치한 정보로 엔티티 생성 + var book = Book( + isbn: bookDetail.isbn, + coverImage: nil, + name: bookDetail.title, + author: bookDetail.author, + publisher: bookDetail.publisher, + publishedAt: bookDetail.publishedDate.toDate() ?? .now, + totalPages: bookDetail.pageCount + ) + + // 3. 표지정보 업데이트 + if let url = URL(string: bookDetail.coverURL) { + let data = try? Data(contentsOf: url) + book.coverImage = data + } + + // 4. 책정보 생성 + try? await bookRepository.createBook(book) + // 5. 책 생성에 실패하든 성공하든 새로운 책제목을 반환 + return book.name + } } } From 902ee0fd2806dab52d532c27686694bd69723997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Wed, 11 Jun 2025 23:09:53 +0900 Subject: [PATCH 07/13] =?UTF-8?q?[#189]=20=ED=88=AC=EB=91=90=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- B.READ/B.READ/Sources/Domain/Entity/Book.swift | 2 +- .../Sources/Presentation/Common/Components/SortMenu.swift | 1 - .../Presentation/Common/ValueObject/RecordDetailVO.swift | 1 - .../Presentation/Library/LibraryView/LibraryGridView.swift | 2 -- .../Presentation/Library/RecordView/RecordBookSection.swift | 1 - .../Presentation/Library/ViewModel/LibraryViewModel.swift | 2 +- .../Library/ViewModel/RecordDetailViewModel.swift | 4 +--- 7 files changed, 3 insertions(+), 10 deletions(-) diff --git a/B.READ/B.READ/Sources/Domain/Entity/Book.swift b/B.READ/B.READ/Sources/Domain/Entity/Book.swift index f4c4440d..8b8dc719 100644 --- a/B.READ/B.READ/Sources/Domain/Entity/Book.swift +++ b/B.READ/B.READ/Sources/Domain/Entity/Book.swift @@ -11,7 +11,7 @@ import Foundation /// - isbn : ISBN /// - coverImg : 표지 /// - name : 제목 -/// - author : 작가 // TODO : 번역가, 옮김이 포함되는지 확인 필요 +/// - author : 작가 /// - publisher : 출판사 /// - publishedAt : 출판일 /// - totalPages: 총 페이지 diff --git a/B.READ/B.READ/Sources/Presentation/Common/Components/SortMenu.swift b/B.READ/B.READ/Sources/Presentation/Common/Components/SortMenu.swift index 460fb2f5..9ebb0fe1 100644 --- a/B.READ/B.READ/Sources/Presentation/Common/Components/SortMenu.swift +++ b/B.READ/B.READ/Sources/Presentation/Common/Components/SortMenu.swift @@ -8,7 +8,6 @@ import Foundation import SwiftUI -// TODO: - [시르] 메뉴 등장 및 사라질때 애니메이션 추가하기 // MARK: - (S)SortMenuButton struct SortMenu: View { @Binding var isOpened: Bool diff --git a/B.READ/B.READ/Sources/Presentation/Common/ValueObject/RecordDetailVO.swift b/B.READ/B.READ/Sources/Presentation/Common/ValueObject/RecordDetailVO.swift index 84487884..974133ed 100644 --- a/B.READ/B.READ/Sources/Presentation/Common/ValueObject/RecordDetailVO.swift +++ b/B.READ/B.READ/Sources/Presentation/Common/ValueObject/RecordDetailVO.swift @@ -109,7 +109,6 @@ extension RecordDetailVO: Hashable { } extension RecordDetailVO { - // TODO: - [시르] 아이디어 필요! VO에 메모, 문장을 넣는방법도 있음 func toEntity(memos: [MemoVO] = [], quotes: [QuoteVO] = []) -> Record { Record( id: self.id, diff --git a/B.READ/B.READ/Sources/Presentation/Library/LibraryView/LibraryGridView.swift b/B.READ/B.READ/Sources/Presentation/Library/LibraryView/LibraryGridView.swift index 9b249cd5..b74c3f24 100644 --- a/B.READ/B.READ/Sources/Presentation/Library/LibraryView/LibraryGridView.swift +++ b/B.READ/B.READ/Sources/Presentation/Library/LibraryView/LibraryGridView.swift @@ -8,7 +8,6 @@ import SwiftUI // MARK: - (S)LibraryGridView -// TODO: - [시르] 그리드 뷰 구현 struct LibraryGridView: View { @EnvironmentObject var coordinator: Coordinator @Binding var records: [RecordCellVO] @@ -25,7 +24,6 @@ struct LibraryGridView: View { ForEach($records) { $record in LibraryGridCell(record: $record) .onTapGesture { - // TODO: - [시르] 머지 후, 뷰 연결 수정 coordinator.push(.libraryDetail(id: record.id)) } } diff --git a/B.READ/B.READ/Sources/Presentation/Library/RecordView/RecordBookSection.swift b/B.READ/B.READ/Sources/Presentation/Library/RecordView/RecordBookSection.swift index 79913429..cf4e2d1b 100644 --- a/B.READ/B.READ/Sources/Presentation/Library/RecordView/RecordBookSection.swift +++ b/B.READ/B.READ/Sources/Presentation/Library/RecordView/RecordBookSection.swift @@ -19,7 +19,6 @@ struct RecordBookSection: View { .resizable() .aspectRatio(contentMode: .fill) } else { - // TODO: - [시르] 사진이 없을때, 들어갈 이미지 or 도형 추가 Image(.exampleCover) .resizable() .aspectRatio(contentMode: .fill) diff --git a/B.READ/B.READ/Sources/Presentation/Library/ViewModel/LibraryViewModel.swift b/B.READ/B.READ/Sources/Presentation/Library/ViewModel/LibraryViewModel.swift index d560dcb1..5d42f609 100644 --- a/B.READ/B.READ/Sources/Presentation/Library/ViewModel/LibraryViewModel.swift +++ b/B.READ/B.READ/Sources/Presentation/Library/ViewModel/LibraryViewModel.swift @@ -132,7 +132,7 @@ private extension LibraryViewModel { // 2. Entity -> VO self.records = infos.map { RecordCellVO(record: $0.record, book: $0.book) } } catch { - // 3. 패치하던중 오류 발생 시 배열은 빈 배열을 반환하고, 에러 메시지를 띄움 + // 3. 패치하던중 오류 발생 시 배열은 빈 배열을 반환 print(error.localizedDescription) self.records = [] } diff --git a/B.READ/B.READ/Sources/Presentation/Library/ViewModel/RecordDetailViewModel.swift b/B.READ/B.READ/Sources/Presentation/Library/ViewModel/RecordDetailViewModel.swift index 039187c5..ffddeef6 100644 --- a/B.READ/B.READ/Sources/Presentation/Library/ViewModel/RecordDetailViewModel.swift +++ b/B.READ/B.READ/Sources/Presentation/Library/ViewModel/RecordDetailViewModel.swift @@ -138,7 +138,6 @@ private extension RecordDetailViewModel { // 4. 생선한 Entity로 업데이트 try await libraryUseCase.editRecord(recordEntity) } catch { - // TODO: - [시르] 수정 실패 에러 메시지 추가 print(error.localizedDescription) } } @@ -158,8 +157,7 @@ private extension RecordDetailViewModel { let recordEntity = record.toEntity(memos: memos, quotes: quotes) // 3. 독서 기록을 삭제 try await libraryUseCase.deleteRecord(recordEntity) - } catch { - // TODO: - [시르] 삭제 실패에 따른 에러 처리 + } catch { print(error.localizedDescription) } } From 3e0942ba843513ff6d502d4911df9027a637fa67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Wed, 11 Jun 2025 23:10:36 +0900 Subject: [PATCH 08/13] =?UTF-8?q?[#189]=20=ED=99=94=EB=A9=B4=20=EA=B0=B1?= =?UTF-8?q?=EC=8B=A0=ED=99=95=EC=9D=B8=20=ED=9B=84=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20-=20=EA=B3=B5=ED=86=B5=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Library/LibraryView/LibraryListCell.swift | 2 - .../Library/LibraryView/RecordStatsView.swift | 56 ------------------- 2 files changed, 58 deletions(-) delete mode 100644 B.READ/B.READ/Sources/Presentation/Library/LibraryView/RecordStatsView.swift diff --git a/B.READ/B.READ/Sources/Presentation/Library/LibraryView/LibraryListCell.swift b/B.READ/B.READ/Sources/Presentation/Library/LibraryView/LibraryListCell.swift index 43dfea62..c76b410a 100644 --- a/B.READ/B.READ/Sources/Presentation/Library/LibraryView/LibraryListCell.swift +++ b/B.READ/B.READ/Sources/Presentation/Library/LibraryView/LibraryListCell.swift @@ -27,9 +27,7 @@ struct LibraryListCell: View { .brStyleFont(.pretendard(.semiBold, size: 18), lineHeight: 1) // 독서 현황 - // TODO: - [시르] Binding으로 만들어야하면, 제작해서 사용 RecordPropertyRow(data: record) -// RecordStatsView(record: $record) // 독서 기간 periodView(record.period) diff --git a/B.READ/B.READ/Sources/Presentation/Library/LibraryView/RecordStatsView.swift b/B.READ/B.READ/Sources/Presentation/Library/LibraryView/RecordStatsView.swift deleted file mode 100644 index a1dd55fe..00000000 --- a/B.READ/B.READ/Sources/Presentation/Library/LibraryView/RecordStatsView.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// RecordStatsView.swift -// B.READ -// -// Created by 심근웅 on 5/23/25. -// - -import SwiftUI - -// TODO: - Binding으로 안만들어도 뷰 반영되면 삭제 예정 -// MARK: - (S)RecordStatsView -struct RecordStatsView: View { - - @Binding private var record: RecordCellVO - - init(record: Binding) { - self._record = record - } - - var body: some View { - HStack(spacing: 12) { - switch record.readingState { - case .notStart: // 기대지수 - PropertyView(SFSymbol.heart.name, record.heart.toString) - case .reading: // 독서진행률 - PropertyView(SFSymbol.timer.name, record.progress.toString, .percent) - case .finished: // 평점 - PropertyView(SFSymbol.star.name, record.star.toString) - } - PropertyView(SFSymbol.memo.name, "\(record.memoCount)", .count) // 메모 - PropertyView(SFSymbol.bubble.name, "\(record.quoteCount)", .count) // 문장 - } // : HStack - .brStyleFont(.pretendard(.regular, size: 14), lineHeight: 1) - } -} - -#Preview { - @Previewable @State var record1 = RecordCellVO( - record: DummyData.dummyRecords[0], - book: DummyData.dummyBooks[0] - ) - @Previewable @State var record2 = RecordCellVO( - record: DummyData.dummyRecords[1], - book: DummyData.dummyBooks[1] - ) - @Previewable @State var record3 = RecordCellVO( - record: DummyData.dummyRecords[2], - book: DummyData.dummyBooks[2] - ) - - PreviewableContainer { - RecordStatsView(record: $record1) - RecordStatsView(record: $record2) - RecordStatsView(record: $record3) - } -} From 71242540864e6cdb0361fd03398d4f91c82ce5f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Wed, 11 Jun 2025 23:10:50 +0900 Subject: [PATCH 09/13] =?UTF-8?q?[#189]=20=ED=94=84=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Common/Components/RecordPropertyRow.swift | 104 +++++++++--------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/B.READ/B.READ/Sources/Presentation/Common/Components/RecordPropertyRow.swift b/B.READ/B.READ/Sources/Presentation/Common/Components/RecordPropertyRow.swift index b9338d93..4c7df546 100644 --- a/B.READ/B.READ/Sources/Presentation/Common/Components/RecordPropertyRow.swift +++ b/B.READ/B.READ/Sources/Presentation/Common/Components/RecordPropertyRow.swift @@ -27,55 +27,55 @@ struct RecordPropertyRow: View { } } -//// MARK: - Preview -//#Preview { -// let notStartdata = RecordCellVO( -// id: DummyData.dummyRecords[0].id, -// isbn: DummyData.dummyRecords[0].isbn, -// title: DummyData.dummyBooks[0].name, -// coverImage: Image(.exampleBook), -// readingState: ReadingState.fromEntity(DummyData.dummyRecords[0].state), -// heart: DummyData.dummyRecords[0].heartCount, -// progress: 0, -// star: DummyData.dummyRecords[0].starCount, -// memoCount: DummyData.dummyRecords[0].memos.count, -// quoteCount: DummyData.dummyRecords[0].quotes.count, -// period: DummyData.dummyRecords[0].period, -// isFavorite: DummyData.dummyRecords[0].isFavorite, -// createdAt: DummyData.dummyRecords[0].createdAt -// ) -// let readingdata = RecordCellVO( -// id: DummyData.dummyRecords[1].id, -// isbn: DummyData.dummyRecords[1].isbn, -// title: DummyData.dummyBooks[1].name, -// coverImage: Image(.exampleBook), -// readingState: ReadingState.fromEntity(DummyData.dummyRecords[1].state), -// heart: DummyData.dummyRecords[1].heartCount, -// progress: 65, -// star: DummyData.dummyRecords[1].starCount, -// memoCount: DummyData.dummyRecords[1].memos.count, -// quoteCount: DummyData.dummyRecords[1].quotes.count, -// period: DummyData.dummyRecords[1].period, -// isFavorite: DummyData.dummyRecords[1].isFavorite, -// createdAt: DummyData.dummyRecords[1].createdAt -// ) -// let finisheddata = RecordCellVO( -// id: DummyData.dummyRecords[2].id, -// isbn: DummyData.dummyRecords[2].isbn, -// title: DummyData.dummyBooks[2].name, -// coverImage: Image(.exampleBook), -// readingState: ReadingState.fromEntity(DummyData.dummyRecords[2].state), -// heart: DummyData.dummyRecords[2].heartCount, -// progress: 65, -// star: DummyData.dummyRecords[2].starCount, -// memoCount: DummyData.dummyRecords[2].memos.count, -// quoteCount: DummyData.dummyRecords[2].quotes.count, -// period: DummyData.dummyRecords[2].period, -// isFavorite: DummyData.dummyRecords[2].isFavorite, -// createdAt: DummyData.dummyRecords[2].createdAt -// ) -// -// RecordPropertyRow(data: notStartdata) -// RecordPropertyRow(data: readingdata) -// RecordPropertyRow(data: finisheddata) -//} +// MARK: - Preview +#Preview { + let notStartdata = RecordCellVO( + id: DummyData.dummyRecords[0].id, + isbn: DummyData.dummyRecords[0].isbn, + title: DummyData.dummyBooks[0].name, + coverImage: Image(.exampleCover), + readingState: ReadingState.fromEntity(DummyData.dummyRecords[0].state), + heart: DummyData.dummyRecords[0].heartCount, + progress: 0, + star: DummyData.dummyRecords[0].starCount, + memoCount: DummyData.dummyRecords[0].memos.count, + quoteCount: DummyData.dummyRecords[0].quotes.count, + period: DummyData.dummyRecords[0].period, + isFavorite: DummyData.dummyRecords[0].isFavorite, + createdAt: DummyData.dummyRecords[0].createdAt + ) + let readingdata = RecordCellVO( + id: DummyData.dummyRecords[1].id, + isbn: DummyData.dummyRecords[1].isbn, + title: DummyData.dummyBooks[1].name, + coverImage: Image(.exampleCover), + readingState: ReadingState.fromEntity(DummyData.dummyRecords[1].state), + heart: DummyData.dummyRecords[1].heartCount, + progress: 65, + star: DummyData.dummyRecords[1].starCount, + memoCount: DummyData.dummyRecords[1].memos.count, + quoteCount: DummyData.dummyRecords[1].quotes.count, + period: DummyData.dummyRecords[1].period, + isFavorite: DummyData.dummyRecords[1].isFavorite, + createdAt: DummyData.dummyRecords[1].createdAt + ) + let finisheddata = RecordCellVO( + id: DummyData.dummyRecords[2].id, + isbn: DummyData.dummyRecords[2].isbn, + title: DummyData.dummyBooks[2].name, + coverImage: Image(.exampleCover), + readingState: ReadingState.fromEntity(DummyData.dummyRecords[2].state), + heart: DummyData.dummyRecords[2].heartCount, + progress: 65, + star: DummyData.dummyRecords[2].starCount, + memoCount: DummyData.dummyRecords[2].memos.count, + quoteCount: DummyData.dummyRecords[2].quotes.count, + period: DummyData.dummyRecords[2].period, + isFavorite: DummyData.dummyRecords[2].isFavorite, + createdAt: DummyData.dummyRecords[2].createdAt + ) + + RecordPropertyRow(data: notStartdata) + RecordPropertyRow(data: readingdata) + RecordPropertyRow(data: finisheddata) +} From f94354d4375f015d4e490f1dd2480600641db68e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Wed, 11 Jun 2025 23:18:43 +0900 Subject: [PATCH 10/13] =?UTF-8?q?[#189]=20LibraryUseCase=20delete=20?= =?UTF-8?q?=EC=BA=90=EC=B9=98=EA=B5=AC=EB=AC=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift b/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift index 9f3fa589..f2ff72b8 100644 --- a/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift +++ b/B.READ/B.READ/Sources/Domain/UseCaseImpl/LibraryUseCaseImpl.swift @@ -118,7 +118,12 @@ final class LibraryUseCaseImpl: LibraryUseCase { } func deleteRecord(_ record: Record) async throws { - try await recordRepository.deleteRecord(record.id) + do { + try await recordRepository.deleteRecord(record.id) + } catch RepositoryError.dataNotFound { + // 삭제에서 이미 존재하지 않으면 무시 + print("이미 삭제된 독서 기록입니다.") + } } func loadRecentUpdatedReadingRecord(maxCount: Int) async throws -> [(Record, Book)] { From 6414f9e9c3f55925fe0f0595624e1e4520b4e958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Thu, 12 Jun 2025 10:53:19 +0900 Subject: [PATCH 11/13] =?UTF-8?q?[#189]=20=EB=B9=8C=EB=93=9C=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=9E=84=EC=8B=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Presentation/Search/View/Main/SearchView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/B.READ/B.READ/Sources/Presentation/Search/View/Main/SearchView.swift b/B.READ/B.READ/Sources/Presentation/Search/View/Main/SearchView.swift index 4cb285b5..f4e13393 100644 --- a/B.READ/B.READ/Sources/Presentation/Search/View/Main/SearchView.swift +++ b/B.READ/B.READ/Sources/Presentation/Search/View/Main/SearchView.swift @@ -142,7 +142,7 @@ struct SearchContentView: View { viewModel: resultViewModel ) .onDisappear { - resultViewModel.send(.clearSelect) +// resultViewModel.send(.cancelSelect) } } else { From 068c947a390aeeb496fb2b62ac196b7384912b79 Mon Sep 17 00:00:00 2001 From: shinseungjae Date: Thu, 12 Jun 2025 13:15:34 +0900 Subject: [PATCH 12/13] =?UTF-8?q?[#189]=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- B.READ/B.READ/Sources/App/RootViewSwitcher.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/B.READ/B.READ/Sources/App/RootViewSwitcher.swift b/B.READ/B.READ/Sources/App/RootViewSwitcher.swift index 5972e9ad..601f7f46 100644 --- a/B.READ/B.READ/Sources/App/RootViewSwitcher.swift +++ b/B.READ/B.READ/Sources/App/RootViewSwitcher.swift @@ -34,8 +34,6 @@ struct RootViewSwitcher: View { LaunchScreen() .task { await DIContainer.config() - // TODO: - [더미]초기값 적용이라 마지막에 제거하기 -// await DummyService.shared.setDummy() try? await Task.sleep(for: .seconds(2)) await MainActor.run { self.isReady = true } } From 93fbffbf0270cffee52f2b99a48a47b26afb7a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=AC=EA=B7=BC=EC=9B=85?= Date: Fri, 13 Jun 2025 10:30:13 +0900 Subject: [PATCH 13/13] =?UTF-8?q?[#189]=20=EB=B9=8C=EB=93=9C=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Presentation/Search/View/Main/SearchView.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/B.READ/B.READ/Sources/Presentation/Search/View/Main/SearchView.swift b/B.READ/B.READ/Sources/Presentation/Search/View/Main/SearchView.swift index ffbb937e..c1afa6c0 100644 --- a/B.READ/B.READ/Sources/Presentation/Search/View/Main/SearchView.swift +++ b/B.READ/B.READ/Sources/Presentation/Search/View/Main/SearchView.swift @@ -143,11 +143,7 @@ struct SearchContentView: View { viewModel: resultViewModel ) .onDisappear { -<<<<<<< feature/#189 -// resultViewModel.send(.cancelSelect) -======= resultViewModel.send(.cancelSelect) ->>>>>>> develop } } else {