-
Notifications
You must be signed in to change notification settings - Fork 0
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
[Feat] 모아보기 기능 구현 #460
base: develop
Are you sure you want to change the base?
[Feat] 모아보기 기능 구현 #460
Changes from 7 commits
c740f84
f56bed9
531761b
28f937d
565e8d8
d678743
5e53430
4058fed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// | ||
// AnnotationCollection.swift | ||
// Reazy | ||
// | ||
// Created by 문인범 on 2/1/25. | ||
// | ||
|
||
import Foundation | ||
|
||
|
||
struct AnnotationCollection: Identifiable, Equatable { | ||
let id: String | ||
|
||
let annotation: AnnotationCase | ||
let commenText: String? | ||
let contents: AttributedString | ||
let pageIndex: Int | ||
|
||
enum AnnotationCase: Equatable { | ||
case highlight | ||
case comment | ||
} | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,4 +18,5 @@ extension Notification.Name { | |
static let isFigureCaptured = Notification.Name("isFigureCaptured") | ||
static let isCollectionCaptured = Notification.Name("isCollectionCaptured") | ||
static let changeHomePaperInfo = Notification.Name("changeHomePaperInfo") | ||
static let didSelectAnnotationCollection = Notification.Name("didSelectAnnotationCollection") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PDFView로 Action을 전달하기 위한 Notification 입니다 |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -131,7 +131,10 @@ extension MainPDFViewModel { | |
|
||
// 각 페이지의 모든 주석을 반복하며 밑줄과 코멘트 아이콘 지우기 | ||
for annotation in page.annotations { | ||
if annotation.value(forAnnotationKey: .contents) != nil { | ||
// if annotation.value(forAnnotationKey: .contents) != nil { | ||
// page.removeAnnotation(annotation) | ||
// } | ||
if let a = annotation.contents, a.split(separator: "|")[0] != "UH" { | ||
page.removeAnnotation(annotation) | ||
} | ||
} | ||
|
@@ -206,6 +209,7 @@ extension MainPDFViewModel { | |
guard let page = selections.first?.pages.first else { return } | ||
|
||
let highlightColor = color.uiColor | ||
let id = UUID() | ||
|
||
selections.forEach { selection in | ||
|
||
|
@@ -236,7 +240,8 @@ extension MainPDFViewModel { | |
let highlight = PDFAnnotation(bounds: bounds, forType: .highlight, withProperties: nil) | ||
highlight.endLineStyle = .none | ||
highlight.color = highlightColor | ||
|
||
highlight.contents = "UH|\(selection.string ?? "nil")|\(color.rawValue)|\(id)" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 모아보기에 필요한 정보들(하이라이트 or 코멘트 인지, 선택된 영역의 String, 사용된 color, id값)을 |
||
|
||
page.addAnnotation(highlight) | ||
pdfDrawer.annotationHistory.append((action: .add(highlight), annotation: highlight, page: page)) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// | ||
// AnnotationCollectionCell.swift | ||
// Reazy | ||
// | ||
// Created by 문인범 on 1/31/25. | ||
// | ||
|
||
import SwiftUI | ||
|
||
|
||
struct AnnotationCollectionCell: View { | ||
let annotation: AnnotationCollection | ||
|
||
var body: some View { | ||
VStack(alignment: .leading, spacing: 0) { | ||
if annotation.annotation == .comment { | ||
HStack(spacing: 0) { | ||
Rectangle() | ||
.foregroundStyle(.point4) | ||
.frame(width: 1, height: 35) | ||
.padding(.trailing, 8) | ||
|
||
Text(annotation.commenText ?? "알 수 없음") | ||
.font(.custom(ReazyFontType.pretendardMediumFont, size: 12)) | ||
.foregroundStyle(.point4) | ||
.lineSpacing(5) | ||
.lineLimit(2) | ||
} | ||
.padding(.bottom, 12) | ||
} | ||
|
||
Text(annotation.contents) | ||
.lineSpacing(5) | ||
.lineLimit(9) | ||
} | ||
.onTapGesture { | ||
NotificationCenter.default.post(name: .didSelectAnnotationCollection, object: nil, userInfo: ["index": annotation.pageIndex]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NotificationCenter를 통해 PDFView에게 액션을 전달합니다. |
||
} | ||
} | ||
} | ||
|
||
|
||
|
||
#Preview { | ||
var attributedString = AttributedString(stringLiteral: "테스트 컨텐츠입니다. 테스트 컨텐츠입니다.테스트 컨텐츠입니다.테스트 컨텐츠입니다.테스트 컨텐츠입니다.") | ||
|
||
let attributes: AttributeContainer = .init([ | ||
.backgroundColor: UIColor.red, | ||
.font: UIFont.init(name: ReazyFontType.pretendardRegularFont, size: 12)!, | ||
]) | ||
|
||
attributedString.setAttributes(attributes) | ||
|
||
let highlight = AnnotationCollection( | ||
id: "", | ||
annotation: .highlight, | ||
commenText: nil, | ||
contents: attributedString, | ||
pageIndex: 0 | ||
) | ||
|
||
let comment = AnnotationCollection( | ||
id: "", | ||
annotation: .comment, | ||
commenText: "테스트 코멘트 입니다.테스트 코멘트 입니다.", | ||
contents: "테스트 컨텐츠입니다. 테스트 컨텐츠입니다.테스트 컨텐츠입니다.테스트 컨텐츠입니다.테스트 컨텐츠입니다.", | ||
pageIndex: 0 | ||
) | ||
|
||
return Group { | ||
AnnotationCollectionCell(annotation: highlight) | ||
Divider() | ||
AnnotationCollectionCell(annotation: comment) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// | ||
// AnnotationCollectionView.swift | ||
// Reazy | ||
// | ||
// Created by 문인범 on 1/31/25. | ||
// | ||
|
||
import SwiftUI | ||
|
||
|
||
struct AnnotationCollectionView: View { | ||
@StateObject private var viewModel: AnnotationCollectionViewModel = .init() | ||
|
||
var body: some View { | ||
ScrollView { | ||
VStack { | ||
ForEach(viewModel.annotations) { annotation in | ||
AnnotationCollectionCell(annotation: annotation) | ||
|
||
divider | ||
.padding(.vertical, 16) | ||
} | ||
} | ||
.padding(.top, 20) | ||
.padding(.horizontal, 24) | ||
} | ||
.onAppear { | ||
viewModel.fetchData() | ||
} | ||
} | ||
|
||
|
||
private var divider: some View { | ||
Rectangle() | ||
.foregroundStyle(.gray500) | ||
.frame(height: 1) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// | ||
// AnnotationCollectionViewModel.swift | ||
// Reazy | ||
// | ||
// Created by 문인범 on 1/31/25. | ||
// | ||
|
||
import Foundation | ||
import UIKit | ||
|
||
|
||
final class AnnotationCollectionViewModel: ObservableObject { | ||
@Published public var annotations: [AnnotationCollection] = [] | ||
|
||
|
||
public func fetchData() { | ||
guard let document = PDFSharedData.shared.document else { return } | ||
let pageCount = document.pageCount | ||
|
||
var resultText = "" | ||
var currentId = "" | ||
var currentContents = "" | ||
|
||
for i in 0 ..< pageCount { | ||
guard let page = document.page(at: i) else { continue } | ||
|
||
page.annotations.forEach { annotation in | ||
switch annotation.markupType { | ||
case .highlight: | ||
if let contents = annotation.contents { | ||
if contents.split(separator: "|")[0] == "UH" || contents.split(separator: "|")[0] == "UC" { | ||
let id = contents.split(separator: "|").last! | ||
|
||
if id != currentId { | ||
if !resultText.isEmpty { | ||
extractAnnotation( | ||
contents: currentContents, | ||
body: resultText.replacingOccurrences(of: "\n", with: " "), | ||
index: i | ||
) | ||
resultText = "" | ||
} | ||
|
||
currentId = String(id) | ||
currentContents = contents | ||
} | ||
|
||
let text = annotation.contents!.split(separator: "|")[1] | ||
if text == " " { return } | ||
|
||
resultText += text | ||
} | ||
} | ||
|
||
default: | ||
break | ||
} | ||
} | ||
|
||
if !resultText.isEmpty { | ||
extractAnnotation( | ||
contents: currentContents, | ||
body: resultText.replacingOccurrences(of: "\n", with: " "), | ||
index: i | ||
) | ||
resultText = "" | ||
} | ||
} | ||
Comment on lines
+24
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재 PDFDocument의 모든 PDFPage를 순회하여 필요한 PDFAnnotation들의 정보를 갖고와 필터링 한 후 Entity로 변환하여 저장합니다. |
||
} | ||
|
||
|
||
|
||
private func extractAnnotation(contents: String, body: String, index: Int) { | ||
let splitedContents = contents.split(separator: "|") | ||
|
||
let id = splitedContents.last! | ||
|
||
switch splitedContents[0] == "UH" { | ||
case true: | ||
guard let color = HighlightColors(rawValue: String(splitedContents[2])) else { break } | ||
var attributedString = AttributedString(body) | ||
let container = AttributeContainer([ | ||
.backgroundColor: color.uiColor, | ||
.font: UIFont(name: "Pretendard-Regular", size: 12)! | ||
]) | ||
|
||
attributedString.setAttributes(container) | ||
|
||
let annotation = AnnotationCollection( | ||
id: String(id), | ||
annotation: .highlight, | ||
commenText: nil, | ||
contents: attributedString, | ||
pageIndex: index | ||
) | ||
|
||
self.annotations.append(annotation) | ||
case false: | ||
let commentText = splitedContents[2] | ||
|
||
var attributedString = AttributedString(commentText) | ||
let container = AttributeContainer([ | ||
.font: UIFont(name: "Pretendard-Medium", size: 12)!, | ||
.foregroundColor: UIColor.point2, | ||
]) | ||
|
||
attributedString.setAttributes(container) | ||
|
||
let annotation = AnnotationCollection( | ||
id: String(id), | ||
annotation: .comment, | ||
commenText: body, | ||
contents: attributedString, | ||
pageIndex: index | ||
) | ||
|
||
self.annotations.append(annotation) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -485,6 +485,8 @@ extension CommentViewModel { | |
} | ||
|
||
func drawUnderline(newComment: Comment) { | ||
var textInputed = false | ||
|
||
for index in newComment.pages { | ||
guard let page = document?.page(at: index) else { continue } | ||
|
||
|
@@ -514,7 +516,13 @@ extension CommentViewModel { | |
|
||
let underline = lineAnnotation(bounds: bounds, forType: .line, withProperties: nil) | ||
|
||
underline.setValue(newComment.id.uuidString, forAnnotationKey: .contents) | ||
if textInputed { | ||
underline.setValue("UC| |" + newComment.id.uuidString, forAnnotationKey: .contents) | ||
} else { | ||
let text = "UC|\(newComment.selectedText)|\(newComment.text)|\(newComment.id.uuidString)" | ||
underline.contents = text | ||
textInputed = true | ||
} | ||
Comment on lines
+519
to
+525
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment에 사용되는 Underline annotation에 정보를 저장합니다. |
||
page.addAnnotation(underline) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
모아보기 뷰에서 사용되는 Entity 입니다