From 40328b26c8ad2ea4aaf06055a91a7a064f0338e9 Mon Sep 17 00:00:00 2001 From: mooninbeom Date: Mon, 11 Nov 2024 16:50:16 +0900 Subject: [PATCH 01/15] =?UTF-8?q?[#182]=20NotificationCenter=20Combine=20?= =?UTF-8?q?=EB=AC=B8=EB=B2=95=EC=9C=BC=EB=A1=9C=20=EB=B3=80=ED=99=98,=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EC=A2=85=EB=A3=8C=EC=8B=9C=20=ED=95=B4?= =?UTF-8?q?=EC=A0=9C=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TableList/VC/ThumbnailTableViewCell.swift | 15 +++++++--- .../VC/ThumbnailTableViewController.swift | 12 ++++++-- .../Views/PDF/PDFViewer/OriginalView.swift | 30 +++++++++++++------ .../VC/ConcentrateViewController.swift | 4 +++ .../PDFViewer/VC/OriginalViewController.swift | 6 +++- 5 files changed, 51 insertions(+), 16 deletions(-) diff --git a/Project/Reazy/Views/PDF/Menu/TableList/VC/ThumbnailTableViewCell.swift b/Project/Reazy/Views/PDF/Menu/TableList/VC/ThumbnailTableViewCell.swift index 8f4227cd..1090f184 100644 --- a/Project/Reazy/Views/PDF/Menu/TableList/VC/ThumbnailTableViewCell.swift +++ b/Project/Reazy/Views/PDF/Menu/TableList/VC/ThumbnailTableViewCell.swift @@ -6,15 +6,15 @@ // import UIKit - +import Combine /** 페이지 리스트 TableView */ class ThumbnailTableViewCell: UITableViewCell { + private var cancellables: Set = [] let pageNum: Int - let thumbnail: UIImage lazy var thumbnailView: UIImageView = { @@ -46,7 +46,11 @@ class ThumbnailTableViewCell: UITableViewCell { setUI() - NotificationCenter.default.addObserver(self, selector: #selector(isMyCell), name: .didSelectThumbnail, object: nil) + NotificationCenter.default.publisher(for: .didSelectThumbnail) + .sink { [weak self] in + self?.isMyCell($0) + } + .store(in: &self.cancellables) } required init?(coder: NSCoder) { @@ -56,6 +60,10 @@ class ThumbnailTableViewCell: UITableViewCell { override func awakeFromNib() { super.awakeFromNib() } + + deinit { + self.cancellables.forEach { $0.cancel() } + } } extension ThumbnailTableViewCell { @@ -85,7 +93,6 @@ extension ThumbnailTableViewCell { } /// Notification에 따른 Cell UI 수정 - @objc private func isMyCell(_ notification: Notification) { guard let obj = notification.userInfo?["num"] as? Int else { return } if obj == self.pageNum { diff --git a/Project/Reazy/Views/PDF/Menu/TableList/VC/ThumbnailTableViewController.swift b/Project/Reazy/Views/PDF/Menu/TableList/VC/ThumbnailTableViewController.swift index 752bc916..a88e6b78 100644 --- a/Project/Reazy/Views/PDF/Menu/TableList/VC/ThumbnailTableViewController.swift +++ b/Project/Reazy/Views/PDF/Menu/TableList/VC/ThumbnailTableViewController.swift @@ -44,6 +44,10 @@ final class ThumbnailTableViewController: UIViewController { setUI() setBinding() } + + deinit { + self.cancellables.forEach { $0.cancel() } + } } // MARK: - UI 초기 설정 @@ -67,11 +71,15 @@ extension ThumbnailTableViewController { } .store(in: &self.cancellables) - NotificationCenter.default.addObserver(self, selector: #selector(redrawScreen), name: UIDevice.orientationDidChangeNotification, object: nil) + NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification) + .sink { [weak self] _ in + self?.redrawScreen() + } + .store(in: &self.cancellables) } - @objc private func redrawScreen() { + private func redrawScreen() { self.thumbnailTableView.reloadData() } } diff --git a/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift b/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift index 45fa3b2f..6b5d583f 100644 --- a/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift +++ b/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift @@ -16,6 +16,7 @@ struct OriginalView: View { @EnvironmentObject var commentViewModel: CommentViewModel @State private var keyboardOffset: CGFloat = 0 + @State private var cancellables: Set = [] private let publisher = NotificationCenter.default.publisher(for: .isCommentTapped) private let screenHeight = UIScreen.main.bounds.height @@ -60,18 +61,26 @@ struct OriginalView: View { let screenHeight = geometry.size.height // 키보드 Notification 설정 - NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { notification in - if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect { - withAnimation { - keyboardOffset = calculateOffset(for: viewModel.commentInputPosition, keyboardFrame: keyboardFrame, screenHeight: screenHeight) + NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification) + .receive(on: DispatchQueue.main) + .sink { + if let keyboardFrame = $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect { + withAnimation { + keyboardOffset = calculateOffset( + for: viewModel.commentInputPosition, keyboardFrame: keyboardFrame, screenHeight: screenHeight) + } } } - } - NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in - withAnimation { - keyboardOffset = 0 + .store(in: &cancellables) + + NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification) + .receive(on: DispatchQueue.main) + .sink { _ in + withAnimation { + keyboardOffset = 0 + } } - } + .store(in: &cancellables) } .animation(.smooth(duration: 0.3), value: viewModel.commentInputPosition) .animation(.smooth(duration: 0.1), value: viewModel.isCommentTapped) @@ -79,6 +88,9 @@ struct OriginalView: View { .onChange(of: viewModel.selectedText) { _, newValue in viewModel.updateBubbleView(selectedText: newValue, bubblePosition: viewModel.bubbleViewPosition) } + .onDisappear { + self.cancellables.forEach { $0.cancel() } + } } } // 키보드 offset 계산 diff --git a/Project/Reazy/Views/PDF/PDFViewer/VC/ConcentrateViewController.swift b/Project/Reazy/Views/PDF/PDFViewer/VC/ConcentrateViewController.swift index fbff9bfe..cbbe7986 100644 --- a/Project/Reazy/Views/PDF/PDFViewer/VC/ConcentrateViewController.swift +++ b/Project/Reazy/Views/PDF/PDFViewer/VC/ConcentrateViewController.swift @@ -57,6 +57,10 @@ final class ConcentrateViewController: UIViewController { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + deinit { + self.cancellables.forEach { $0.cancel() } + } } // MARK: - 초기 세팅 diff --git a/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift b/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift index 541623cc..90c8c637 100644 --- a/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift +++ b/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift @@ -65,6 +65,10 @@ final class OriginalViewController: UIViewController { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + deinit { + self.cancellable.forEach { $0.cancel() } + } } // MARK: - 초기 설정 @@ -120,7 +124,7 @@ extension OriginalViewController { /// 데이터 Binding private func setBinding() { // ViewModel toolMode의 변경 감지해서 pencil이랑 eraser일 때만 펜슬 제스처 인식하게 - viewModel.$toolMode + self.viewModel.$toolMode .sink { [weak self] mode in self?.updateGestureRecognizer(for: mode) } From 7548b03ea1f045a56042a290ffacfc5b00c46d7c Mon Sep 17 00:00:00 2001 From: wltnryu Date: Wed, 13 Nov 2024 23:26:24 +0900 Subject: [PATCH 02/15] =?UTF-8?q?[#197]=20Dark=20Mode=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Reazy.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Reazy.xcodeproj/project.pbxproj b/Reazy.xcodeproj/project.pbxproj index 52334ed9..0b8a28c1 100644 --- a/Reazy.xcodeproj/project.pbxproj +++ b/Reazy.xcodeproj/project.pbxproj @@ -386,6 +386,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + INFOPLIST_KEY_UIUserInterfaceStyle = Light; IPHONEOS_DEPLOYMENT_TARGET = 17.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -421,6 +422,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + INFOPLIST_KEY_UIUserInterfaceStyle = Light; IPHONEOS_DEPLOYMENT_TARGET = 17.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", From 86b34ea83034108db4fac2d90ccdb4b27bfd3ee9 Mon Sep 17 00:00:00 2001 From: minjung0067 Date: Fri, 15 Nov 2024 10:08:38 +0900 Subject: [PATCH 03/15] =?UTF-8?q?[#200]=20bubbleView=20->=20translateView?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Project/Reazy/Views/PDF/BubbleView.swift | 14 +++++++------- .../Reazy/Views/PDF/BubbleViewOlderVer.swift | 4 ++-- Project/Reazy/Views/PDF/MainPDFView.swift | 2 +- .../Views/PDF/PDFViewer/OriginalView.swift | 8 ++++---- .../PDFViewer/VC/OriginalViewController.swift | 6 +++--- .../ViewModels/MainPDFViewModel.swift | 18 +++++++++--------- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Project/Reazy/Views/PDF/BubbleView.swift b/Project/Reazy/Views/PDF/BubbleView.swift index 7bd6e68b..847fb7ff 100644 --- a/Project/Reazy/Views/PDF/BubbleView.swift +++ b/Project/Reazy/Views/PDF/BubbleView.swift @@ -2,12 +2,12 @@ import SwiftUI import Translation @available(iOS 18.0, *) -struct BubbleView: View { +struct TranslateView: View { @EnvironmentObject var viewModel: MainPDFViewModel @EnvironmentObject var floatingViewModel: FloatingViewModel @Binding var selectedText: String - @Binding var bubblePosition: CGRect + @Binding var translatePosition: CGRect @Binding var isPaperViewFirst: Bool @State private var targetText = "" // 번역 결과 텍스트 @@ -125,15 +125,15 @@ struct BubbleView: View { } } .onAppear { - bubblePositionForScreen(bubblePosition, in: geometry.size) - textWidth = bubblePosition.width * 1.5 // 글자 수 적을 때 너비 여유롭게 + bubblePositionForScreen(translatePosition, in: geometry.size) + textWidth = translatePosition.width * 1.5 // 글자 수 적을 때 너비 여유롭게 triggerTranslation() } .position(updatedBubblePosition) .onChange(of: selectedText) { isTranslationComplete = false // 번역 완료 되었을 때 뷰 다시 그리게 false 처리 - bubblePositionForScreen(bubblePosition, in: geometry.size) - textWidth = bubblePosition.width * 1.5 + bubblePositionForScreen(translatePosition, in: geometry.size) + textWidth = translatePosition.width * 1.5 triggerTranslation() } .onPreferenceChange(ViewHeightKey.self) { height in @@ -167,7 +167,7 @@ struct BubbleView: View { target: Locale.Language(identifier: "ko")) } - // BubbleView 위치 조정하는 함수 + // TranslateView 위치 조정하는 함수 private func bubblePositionForScreen(_ rect: CGRect, in screenSize: CGSize) { if floatingViewModel.splitMode { // 스플릿 뷰 켜져 있으면 항상 아래에 붙게 // 말풍선이 선택 영역 아래에 붙음 diff --git a/Project/Reazy/Views/PDF/BubbleViewOlderVer.swift b/Project/Reazy/Views/PDF/BubbleViewOlderVer.swift index e864acf5..05f6463d 100644 --- a/Project/Reazy/Views/PDF/BubbleViewOlderVer.swift +++ b/Project/Reazy/Views/PDF/BubbleViewOlderVer.swift @@ -1,5 +1,5 @@ // -// BubbleViewOlderVer.swift +// TranslateViewOlderVer.swift // Reazy // // Created by Minjung Lee on 10/31/24. @@ -7,7 +7,7 @@ import SwiftUI -struct BubbleViewOlderVer: View { +struct TranslateViewOlderVer: View { var body: some View { // 18.0 미만 버전에서 보여줄 화면 diff --git a/Project/Reazy/Views/PDF/MainPDFView.swift b/Project/Reazy/Views/PDF/MainPDFView.swift index 28fcddf2..ceaf6cc4 100644 --- a/Project/Reazy/Views/PDF/MainPDFView.swift +++ b/Project/Reazy/Views/PDF/MainPDFView.swift @@ -422,7 +422,7 @@ struct MainPDFView: View { // 18 미만 버전에서 번역 모드 on 일 때 말풍선 띄우기 if #unavailable(iOS 18.0) { if mainPDFViewModel.toolMode == .translate { - BubbleViewOlderVer() + TranslateViewOlderVer() } } } diff --git a/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift b/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift index 61500962..84890394 100644 --- a/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift +++ b/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift @@ -35,13 +35,13 @@ struct OriginalView: View { } .onTapGesture { // 터치 시 말풍선 뷰를 숨기는 처리 추가 - viewModel.updateBubbleView(selectedText: "", bubblePosition: .zero) + viewModel.updateTranslateView(selectedText: "", translateBubblePosition: .zero) } // 번역에 사용되는 말풍선뷰 if viewModel.toolMode == .translate { if #available(iOS 18.0, *) { - if viewModel.isBubbleViewVisible { - BubbleView(selectedText: $viewModel.selectedText, bubblePosition: $viewModel.bubbleViewPosition, isPaperViewFirst: $viewModel.isPaperViewFirst) + if viewModel.isTranslateViewVisible { + TranslateView(selectedText: $viewModel.selectedText, translatePosition: $viewModel.translateViewPosition, isPaperViewFirst: $viewModel.isPaperViewFirst) .environmentObject(floatingViewModel) .environmentObject(viewModel) } @@ -83,7 +83,7 @@ struct OriginalView: View { .animation(.smooth(duration: 0.1), value: viewModel.isCommentTapped) .transition(.move(edge: .bottom).combined(with: .opacity)) .onChange(of: viewModel.selectedText) { _, newValue in - viewModel.updateBubbleView(selectedText: newValue, bubblePosition: viewModel.bubbleViewPosition) + viewModel.updateTranslateView(selectedText: newValue, translateBubblePosition: viewModel.translateViewPosition) } .onDisappear { self.cancellables.forEach { $0.cancel() } diff --git a/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift b/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift index 26bce7fe..fd937444 100644 --- a/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift +++ b/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift @@ -178,7 +178,7 @@ extension OriginalViewController { guard let selection = self.mainPDFView.currentSelection else { // 선택된 텍스트가 없을 때 특정 액션 self.viewModel.selectedText = "" // 선택된 텍스트 초기화 - self.viewModel.bubbleViewVisible = false // 말풍선 뷰 숨김 + self.viewModel.translateViewVisible = false // 말풍선 뷰 숨김 return } @@ -210,8 +210,8 @@ extension OriginalViewController { DispatchQueue.main.async { // ViewModel에 선택된 텍스트와 위치 업데이트 self.viewModel.selectedText = selectedText - self.viewModel.bubbleViewPosition = screenPosition // 위치 업데이트 - self.viewModel.bubbleViewVisible = !selectedText.isEmpty // 텍스트가 있을 때만 보여줌 + self.viewModel.translateViewPosition = screenPosition // 위치 업데이트 + self.viewModel.translateViewVisible = !selectedText.isEmpty // 텍스트가 있을 때만 보여줌 self.viewModel.commentSelection = selection self.viewModel.commentInputPosition = commentPosition diff --git a/Project/Reazy/Views/PDF/PDFViewer/ViewModels/MainPDFViewModel.swift b/Project/Reazy/Views/PDF/PDFViewer/ViewModels/MainPDFViewModel.swift index d738f265..d015ba2a 100644 --- a/Project/Reazy/Views/PDF/PDFViewer/ViewModels/MainPDFViewModel.swift +++ b/Project/Reazy/Views/PDF/PDFViewer/ViewModels/MainPDFViewModel.swift @@ -23,7 +23,7 @@ final class MainPDFViewModel: ObservableObject { @Published var selectedText: String = "" { didSet { /// 선택된 텍스트가 변경될 때 추가 작업 - updateBubbleView(selectedText: selectedText, bubblePosition: bubbleViewPosition) + updateTranslateView(selectedText: selectedText, translateBubblePosition: translateViewPosition) if isCommentVisible { updateCommentPosition(at: commentInputPosition) @@ -43,8 +43,8 @@ final class MainPDFViewModel: ObservableObject { @Published var isPaperViewFirst: Bool = true // BubbleView의 상태와 위치 - @Published var bubbleViewVisible: Bool = false - @Published var bubbleViewPosition: CGRect = .zero + @Published var translateViewVisible: Bool = false + @Published var translateViewPosition: CGRect = .zero // 하이라이트 색상 @Published var selectedHighlightColor: HighlightColors = .yellow @@ -397,22 +397,22 @@ extension MainPDFViewModel { } extension MainPDFViewModel { - public var isBubbleViewVisible: Bool { + public var isTranslateViewVisible: Bool { get { - self.toolMode == .translate && self.bubbleViewVisible && !self.selectedText.isEmpty + self.toolMode == .translate && self.translateViewVisible && !self.selectedText.isEmpty } } // 선택된 텍스트가 있을 경우 BubbleView를 보이게 하고 위치를 업데이트하는 메서드 - public func updateBubbleView(selectedText: String, bubblePosition: CGRect) { + public func updateTranslateView(selectedText: String, translateBubblePosition: CGRect) { // 선택된 텍스트가 있을 경우 BubbleView를 보이게 하고 위치를 업데이트 if !selectedText.isEmpty { - bubbleViewVisible = true - self.bubbleViewPosition = bubblePosition + translateViewVisible = true + self.translateViewPosition = translateBubblePosition } else { - bubbleViewVisible = false + translateViewVisible = false } } } From 19e28987e38dcb20f675ea73013985740c9eaf22 Mon Sep 17 00:00:00 2001 From: wltnryu Date: Fri, 15 Nov 2024 14:51:39 +0900 Subject: [PATCH 04/15] =?UTF-8?q?[#201]=20=EA=B2=80=EC=83=89=EC=B0=BD=20xm?= =?UTF-8?q?ark=20=EB=8D=94=EB=B8=94=20=EB=A0=8C=EB=8D=94=EB=A7=81=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Project/Reazy/DesignSystem/Views/SearchBar.swift | 4 +++- Project/Reazy/Views/PDF/MainPDFView.swift | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Project/Reazy/DesignSystem/Views/SearchBar.swift b/Project/Reazy/DesignSystem/Views/SearchBar.swift index 0e71a93a..f095f9dc 100644 --- a/Project/Reazy/DesignSystem/Views/SearchBar.swift +++ b/Project/Reazy/DesignSystem/Views/SearchBar.swift @@ -25,8 +25,10 @@ struct SearchBar: View { self.text = "" }, label: { Image(systemName: "xmark.circle.fill") - }) + .id(text) + .transition(.opacity) + .animation(.easeInOut(duration: 0.2), value: text) } else { EmptyView() } diff --git a/Project/Reazy/Views/PDF/MainPDFView.swift b/Project/Reazy/Views/PDF/MainPDFView.swift index 28fcddf2..f1293c68 100644 --- a/Project/Reazy/Views/PDF/MainPDFView.swift +++ b/Project/Reazy/Views/PDF/MainPDFView.swift @@ -287,6 +287,9 @@ struct MainPDFView: View { .font(.system(size: 16)) .foregroundStyle(.gray600) } + .id(titleText) + .transition(.opacity) + .animation(.easeInOut(duration: 0.2), value: titleText) .padding(.trailing, 8) } From 94aa53de6bcec2a1fd899788c8e3452256490797 Mon Sep 17 00:00:00 2001 From: wltnryu Date: Fri, 15 Nov 2024 15:27:41 +0900 Subject: [PATCH 05/15] =?UTF-8?q?[#201]=20=EC=A6=90=EA=B2=A8=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=ED=95=9C=20=EB=AC=B8=EC=84=9C=20=EB=A9=98=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Views/Home/Paper/PaperListView.swift | 3 +- Project/Reazy/Views/PDF/MainPDFView.swift | 118 +++++++++--------- 2 files changed, 60 insertions(+), 61 deletions(-) diff --git a/Project/Reazy/Views/Home/Paper/PaperListView.swift b/Project/Reazy/Views/Home/Paper/PaperListView.swift index 4a76c8f9..d239e676 100644 --- a/Project/Reazy/Views/Home/Paper/PaperListView.swift +++ b/Project/Reazy/Views/Home/Paper/PaperListView.swift @@ -64,7 +64,6 @@ struct PaperListView: View { Button(action: { isFavoritesSelected = true - // TODO: - 즐겨찾기 filter 적용 필요 }, label: { Text("즐겨찾기") .reazyFont(isFavoritesSelected ? .text3 : .h2) @@ -97,7 +96,7 @@ struct PaperListView: View { .scaledToFit() .frame(height: 146) .padding(.bottom, 11) - Text("새로운 논문을 가져와주세요") + Text(isFavoritesSelected ? "즐겨찾기한 논문이 없어요" : "새로운 논문을 가져와주세요") .reazyFont(.h5) .foregroundStyle(.gray550) .padding(.bottom, 80) diff --git a/Project/Reazy/Views/PDF/MainPDFView.swift b/Project/Reazy/Views/PDF/MainPDFView.swift index f1293c68..e8e02a45 100644 --- a/Project/Reazy/Views/PDF/MainPDFView.swift +++ b/Project/Reazy/Views/PDF/MainPDFView.swift @@ -119,65 +119,65 @@ struct MainPDFView: View { .padding(.horizontal, 22) .background(.primary3) - HStack(spacing: 0) { - Spacer() + HStack(spacing: 0) { + Spacer() + + ForEach(WriteButton.allCases, id: \.self) { btn in + // 조건부 Padding값 조정 + let trailingPadding: CGFloat = { + if selectedButton == .highlight && btn == .highlight { + return .zero + } else if btn == .translate { + return .zero + } else { + return 32 + } + }() - ForEach(WriteButton.allCases, id: \.self) { btn in - // 조건부 Padding값 조정 - let trailingPadding: CGFloat = { - if selectedButton == .highlight && btn == .highlight { - return .zero - } else if btn == .translate { - return .zero - } else { - return 32 - } - }() - - // [Comment], [Highlight], [Pencil], [Eraser], [Translate] 버튼 - WriteViewButton(button: $selectedButton, HighlightColors: $selectedColor, buttonOwner: btn) { - // MARK: - 작성 관련 버튼 action 입력 - /// 위의 다섯 개 버튼의 action 로직은 이곳에 입력해 주세요 - if selectedButton == btn { - selectedButton = nil - mainPDFViewModel.toolMode = .none - } else { - selectedButton = btn - } - - switch selectedButton { - case .translate: - NotificationCenter.default.post(name: .PDFViewSelectionChanged, object: nil) - mainPDFViewModel.toolMode = .translate - - case .pencil: - mainPDFViewModel.toolMode = .pencil - - case .eraser: - mainPDFViewModel.toolMode = .eraser - - case .highlight: - mainPDFViewModel.toolMode = .highlight - - case .comment: - mainPDFViewModel.toolMode = .comment - - default: - // 전체 비활성화 - mainPDFViewModel.toolMode = .none - } + // [Comment], [Highlight], [Pencil], [Eraser], [Translate] 버튼 + WriteViewButton(button: $selectedButton, HighlightColors: $selectedColor, buttonOwner: btn) { + // MARK: - 작성 관련 버튼 action 입력 + /// 위의 다섯 개 버튼의 action 로직은 이곳에 입력해 주세요 + if selectedButton == btn { + selectedButton = nil + mainPDFViewModel.toolMode = .none + } else { + selectedButton = btn } - .padding(.trailing, trailingPadding) - // Highlight 버튼이 선택될 경우 색상을 선택 - if selectedButton == .highlight && btn == .highlight { - highlightColorSelector() + switch selectedButton { + case .translate: + NotificationCenter.default.post(name: .PDFViewSelectionChanged, object: nil) + mainPDFViewModel.toolMode = .translate + + case .pencil: + mainPDFViewModel.toolMode = .pencil + + case .eraser: + mainPDFViewModel.toolMode = .eraser + + case .highlight: + mainPDFViewModel.toolMode = .highlight + + case .comment: + mainPDFViewModel.toolMode = .comment + + default: + // 전체 비활성화 + mainPDFViewModel.toolMode = .none } } + .padding(.trailing, trailingPadding) - Spacer() + // Highlight 버튼이 선택될 경우 색상을 선택 + if selectedButton == .highlight && btn == .highlight { + highlightColorSelector() + } } - .background(.clear) + + Spacer() + } + .background(.clear) } @@ -186,12 +186,12 @@ struct MainPDFView: View { GeometryReader { geometry in ZStack { - ZStack { - if isVertical { - splitLayout(for: .vertical) - } else { - splitLayout(for: .horizontal) - } + ZStack { + if isVertical { + splitLayout(for: .vertical) + } else { + splitLayout(for: .horizontal) + } } HStack(spacing: 0){ @@ -313,7 +313,7 @@ struct MainPDFView: View { } .frame(width: isVertical ? 383 : 567) - + }, leftView: { HStack(spacing: 0) { From 430f2139f61fb1bec1e76bfdc695fdbca40ed31d Mon Sep 17 00:00:00 2001 From: mooninbeom Date: Fri, 15 Nov 2024 16:39:34 +0900 Subject: [PATCH 06/15] =?UTF-8?q?[#206]=20=ED=82=A4=EB=B3=B4=EB=93=9C=20re?= =?UTF-8?q?turn=20=EC=95=A1=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Project/Reazy/Views/Home/HomeView.swift | 28 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/Project/Reazy/Views/Home/HomeView.swift b/Project/Reazy/Views/Home/HomeView.swift index 148058a0..e742bae0 100644 --- a/Project/Reazy/Views/Home/HomeView.swift +++ b/Project/Reazy/Views/Home/HomeView.swift @@ -383,12 +383,28 @@ private struct RenamePaperTitleView: View { } .frame(width: 400, height: isEditingTitle ? 52 : 180) .overlay(alignment: isEditingTitle ? .center : .topLeading) { - TextField( isEditingTitle ? "제목을 입력해주세요." : "내용을 입력해주세요.", text: $text, axis: .vertical) - .lineLimit( isEditingTitle ? 1 : 6) - .padding(.horizontal, 16) - .padding(.vertical, isEditingTitle ? 0 : 16) - .font(.custom(ReazyFontType.pretendardMediumFont, size: 16)) - .foregroundStyle(.gray800) + + if isEditingTitle { + TextField("제목을 입력해주세요.", text: $text) + .submitLabel(.done) + .onSubmit { + pdfFileManager.updateTitle(at: paperInfo.id, title: text) + isEditingTitle = false + } + .lineLimit( isEditingTitle ? 1 : 6) + .padding(.horizontal, 16) + .padding(.vertical, isEditingTitle ? 0 : 16) + .font(.custom(ReazyFontType.pretendardMediumFont, size: 16)) + .foregroundStyle(.gray800) + } else { + TextField("내용을 입력해주세요.", text: $text, axis: .vertical) + .submitLabel(.return) + .lineLimit(6) + .padding(.horizontal, 16) + .padding(.vertical, 16) + .font(.custom(ReazyFontType.pretendardMediumFont, size: 16)) + .foregroundStyle(.gray800) + } } .overlay(alignment: isEditingTitle ? .trailing : .bottomTrailing) { if !self.text.isEmpty { From 2cb95aa9bf0f2e97233c61e2f75e10e1226a7fb6 Mon Sep 17 00:00:00 2001 From: Bluecho97 Date: Fri, 15 Nov 2024 17:04:08 +0900 Subject: [PATCH 07/15] =?UTF-8?q?[#202]=20=ED=95=98=EC=9D=B4=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=EC=8B=9C=EA=B0=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Views/PDF/PDFViewer/VC/OriginalViewController.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift b/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift index 7650cfcb..8f78c724 100644 --- a/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift +++ b/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift @@ -162,14 +162,18 @@ extension OriginalViewController { // 현재 드래그된 텍스트 가져오는 함수 NotificationCenter.default.publisher(for: .PDFViewSelectionChanged) - .debounce(for: .milliseconds(350), scheduler: RunLoop.main) + .debounce(for: .milliseconds(700), scheduler: RunLoop.main) + .sink { [weak self] _ in guard let self = self else { return } + switch self.viewModel.toolMode { + case .highlight: DispatchQueue.main.async { self.viewModel.highlightText(in: self.mainPDFView, with: self.viewModel.selectedHighlightColor) // 하이라이트 기능 } + case .translate, .comment: guard let selection = self.mainPDFView.currentSelection else { // 선택된 텍스트가 없을 때 특정 액션 @@ -219,6 +223,7 @@ extension OriginalViewController { // 텍스트 선택 후 딜레이 self.selectionWorkItem = workItem DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: workItem) + default: return } From 3755a7f145d96427a4346b22fe2bcf18427485f6 Mon Sep 17 00:00:00 2001 From: wltnryu Date: Fri, 15 Nov 2024 17:36:57 +0900 Subject: [PATCH 08/15] =?UTF-8?q?[#205]=20View=20=ED=95=98=EB=8B=A8?= =?UTF-8?q?=EC=97=90=20comment=20=EC=9E=91=EC=84=B1=20=EC=8B=9C=20?= =?UTF-8?q?=EC=83=81=EB=8B=A8=EB=B0=94=EB=A5=BC=20=EB=8D=AE=EB=8A=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extensions/View+NavigationBar.swift | 143 +++++++++--------- .../PDF/Floating/FloatingSplitView.swift | 1 + Project/Reazy/Views/PDF/MainPDFView.swift | 12 +- 3 files changed, 80 insertions(+), 76 deletions(-) diff --git a/Project/Reazy/DesignSystem/Extensions/View+NavigationBar.swift b/Project/Reazy/DesignSystem/Extensions/View+NavigationBar.swift index 99ae2896..8f865ab4 100644 --- a/Project/Reazy/DesignSystem/Extensions/View+NavigationBar.swift +++ b/Project/Reazy/DesignSystem/Extensions/View+NavigationBar.swift @@ -9,81 +9,88 @@ import SwiftUI // MARK: - 커스텀 Navigation Bar struct CustomNavigationBarModifier: ViewModifier where C : View, L : View, R : View { - let centerView: (() -> C)? - let leftView: (() -> L)? - let rightView: (() -> R)? - - init(centerView: (() -> C)? = nil, leftView: (() -> L)? = nil, rightView: (() -> R)? = nil) { - self.centerView = centerView - self.leftView = leftView - self.rightView = rightView - } - - func body(content: Content) -> some View { - VStack(spacing: 0) { - ZStack { - HStack { - self.leftView?() - Spacer() - self.rightView?() - } - .frame(height: 51) - .padding(.horizontal, 20) - - HStack { - Spacer() - self.centerView?() - Spacer() + let centerView: (() -> C)? + let leftView: (() -> L)? + let rightView: (() -> R)? + + init(centerView: (() -> C)? = nil, leftView: (() -> L)? = nil, rightView: (() -> R)? = nil) { + self.centerView = centerView + self.leftView = leftView + self.rightView = rightView + } + + func body(content: Content) -> some View { + VStack(spacing: 0) { + ZStack { + HStack { + self.leftView?() + Spacer() + self.rightView?() + } + .frame(height: 51) + .padding(.horizontal, 20) + + HStack { + Spacer() + self.centerView?() + Spacer() + } + } + .padding(.top, 10) + .background(.primary2) + .zIndex(1) + + Rectangle() + .frame(height: 1) + .foregroundStyle(Color(hex: "CCCEE1")) + .zIndex(1) + + content + .zIndex(0) } - } - .padding(.top, 10) - .background(.primary2) - - content + .navigationBarHidden(true) } - .navigationBarHidden(true) - } } private struct WillDisappearModifier: ViewModifier { - let callback: () -> Void - - func body(content: Content) -> some View { - content - .onDisappear { - callback() - } - } + let callback: () -> Void + + func body(content: Content) -> some View { + content + .onDisappear { + callback() + } + } } extension View { - func onWillDisappear(_ perform: @escaping () -> Void) -> some View { - self.modifier(WillDisappearModifier(callback: perform)) - } - - func customNavigationBar ( - centerView: @escaping (() -> C), - leftView: @escaping (() -> L), - rightView: @escaping (() -> R) - ) -> some View where C: View, L: View, R: View { - modifier( - CustomNavigationBarModifier(centerView: centerView, leftView: leftView, rightView: rightView) - ) - } - - func customNavigationBar ( - centerView: @escaping (() -> V) - ) -> some View where V: View { - modifier( - CustomNavigationBarModifier( - centerView: centerView, - leftView: { - EmptyView() - }, rightView: { - EmptyView() - } - ) - ) - } + func onWillDisappear(_ perform: @escaping () -> Void) -> some View { + self.modifier(WillDisappearModifier(callback: perform)) + } + + func customNavigationBar ( + centerView: @escaping (() -> C), + leftView: @escaping (() -> L), + rightView: @escaping (() -> R) + ) -> some View where C: View, L: View, R: View { + modifier( + CustomNavigationBarModifier(centerView: centerView, leftView: leftView, rightView: rightView) + ) + } + + func customNavigationBar ( + centerView: @escaping (() -> V) + ) -> some View where V: View { + modifier( + CustomNavigationBarModifier( + centerView: centerView, + leftView: { + EmptyView() + }, rightView: { + EmptyView() + } + ) + ) + } } diff --git a/Project/Reazy/Views/PDF/Floating/FloatingSplitView.swift b/Project/Reazy/Views/PDF/Floating/FloatingSplitView.swift index 06f05682..9da1d2f1 100644 --- a/Project/Reazy/Views/PDF/Floating/FloatingSplitView.swift +++ b/Project/Reazy/Views/PDF/Floating/FloatingSplitView.swift @@ -157,6 +157,7 @@ struct FloatingSplitView: View { .frame(height: isVertical ? geometry.size.height * 0.2 : geometry.size.height * 0.3) } } + .background(.gray100) .onAppear { updateOrientation(with: geometry) } diff --git a/Project/Reazy/Views/PDF/MainPDFView.swift b/Project/Reazy/Views/PDF/MainPDFView.swift index e8e02a45..d26febb4 100644 --- a/Project/Reazy/Views/PDF/MainPDFView.swift +++ b/Project/Reazy/Views/PDF/MainPDFView.swift @@ -17,7 +17,6 @@ struct MainPDFView: View { @EnvironmentObject var navigationCoordinator: NavigationCoordinator @EnvironmentObject private var pdfFileManager: PDFFileManager - @StateObject public var mainPDFViewModel: MainPDFViewModel @StateObject private var floatingViewModel: FloatingViewModel = .init() @StateObject public var commentViewModel: CommentViewModel @@ -38,9 +37,6 @@ struct MainPDFView: View { GeometryReader { geometry in ZStack { VStack(spacing: 0) { - Divider() - .foregroundStyle(Color(hex: "CCCEE1")) - ZStack { HStack(spacing: 0) { Button(action: { @@ -101,7 +97,6 @@ struct MainPDFView: View { }) { RoundedRectangle(cornerRadius: 6) .frame(width: 26, height: 26) - // MARK: - 부리꺼 : 색상 적용 필요 .foregroundStyle(isFigSelected ? Color(hex: "5F5DAA") : .clear) .overlay ( ZStack { @@ -178,11 +173,13 @@ struct MainPDFView: View { Spacer() } .background(.clear) - } + .zIndex(1) - Divider() + Rectangle() + .frame(height: 1) .foregroundStyle(Color(hex: "CCCEE1")) + .zIndex(1) GeometryReader { geometry in ZStack { @@ -366,7 +363,6 @@ struct MainPDFView: View { } .onDisappear { mainPDFViewModel.savePDF(pdfView: mainPDFViewModel.pdfDrawer.pdfView) - // TODO: - [브리] commentViewModel에 있는 comments랑 buttonGroup 배열 두 개 저장하는 거 여기서 } .onChange(of: geometry.size) { updateOrientation(with: geometry) From 3ccbdcdd26b6c14d2eef156391354dfaba8f50a5 Mon Sep 17 00:00:00 2001 From: minjung0067 Date: Fri, 15 Nov 2024 17:37:56 +0900 Subject: [PATCH 09/15] =?UTF-8?q?[#200]=20translate=20=EB=A7=90=ED=92=8D?= =?UTF-8?q?=EC=84=A0=20=EC=A0=84=EC=B2=B4=20popover=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Project/Reazy/Views/PDF/BubbleView.swift | 222 ------------------ .../Views/PDF/PDFViewer/OriginalView.swift | 7 +- .../PDFViewer/VC/OriginalViewController.swift | 2 +- Project/Reazy/Views/PDF/TranslateView.swift | 134 +++++++++++ ...rVer.swift => TranslateViewOlderVer.swift} | 0 5 files changed, 136 insertions(+), 229 deletions(-) delete mode 100644 Project/Reazy/Views/PDF/BubbleView.swift create mode 100644 Project/Reazy/Views/PDF/TranslateView.swift rename Project/Reazy/Views/PDF/{BubbleViewOlderVer.swift => TranslateViewOlderVer.swift} (100%) diff --git a/Project/Reazy/Views/PDF/BubbleView.swift b/Project/Reazy/Views/PDF/BubbleView.swift deleted file mode 100644 index 847fb7ff..00000000 --- a/Project/Reazy/Views/PDF/BubbleView.swift +++ /dev/null @@ -1,222 +0,0 @@ -import SwiftUI -import Translation - -@available(iOS 18.0, *) -struct TranslateView: View { - @EnvironmentObject var viewModel: MainPDFViewModel - @EnvironmentObject var floatingViewModel: FloatingViewModel - - @Binding var selectedText: String - @Binding var translatePosition: CGRect - @Binding var isPaperViewFirst: Bool - - @State private var targetText = "" // 번역 결과 텍스트 - @State private var configuration: TranslationSession.Configuration? - - @State private var maxBubbleWidth: CGFloat = 400 // bubble 최대 너비 - @State private var maxBubbleHeight: CGFloat = 280 // bubble 최대 높이 - @State private var textHeight: CGFloat = 0 // 텍스트 높이 저장 - @State private var textWidth: CGFloat = 100 // 텍스트 너비 저장 - - // 말풍선 붙는 위치 - enum BubbleDirection { - case left, right, bottom - } - - @State private var bubbleDirection: BubbleDirection = .left - - @State private var updatedBubblePosition: CGPoint = .zero // 조정된 bubble view 위치 - @State private var isTranslationComplete: Bool = false // 번역 완료 되었는지 확인해 뷰 새로 그리기 위한 flag - - var body: some View { - // 18.0 이상 버전에서 보여줄 화면 - GeometryReader { geometry in - VStack(alignment: .center, spacing: 0) { - if isTranslationComplete { - ZStack (alignment: .center) { - // 배경에 깔릴 테두리 용 삼각형 - Image(systemName: "triangle.fill") - .resizable() - .foregroundStyle(.primary3) - .frame(width: 30, height: 22) // 크기 지정 (테두리 역할이라 + 2씩) - .rotationEffect( - Angle(degrees: { - switch bubbleDirection { - case .left: - return 90 - case .right: - return 270 - case .bottom: - return 0 - } - }()) - ) - .offset( - x: { - switch bubbleDirection { - case .left: - return (min(textWidth, maxBubbleWidth) / 2) + 2 - case .right: - return -(min(textWidth, maxBubbleWidth) / 2) - 2 - case .bottom: - return 0 - } - }(), - y: bubbleDirection == .bottom ? -(min(textHeight, maxBubbleHeight) / 2) - 2 : 0 // 전체 높이의 중간에 화살표가 오게 조정 - ) - .shadow(color: Color(hex: "#767676").opacity(0.25), radius: 6, x: 0, y: 2) - - RoundedRectangle(cornerRadius: 8) - .fill(.gray200) - .stroke(.primary3, lineWidth: 1) - .frame(width: min(textWidth, maxBubbleWidth), height: min(textHeight, maxBubbleHeight)) - .shadow(color: Color(hex: "#767676").opacity(0.25), radius: 6, x: 0, y: 2) - - // 말풍선 옆에 붙어있는 삼각형 - Image(systemName: "triangle.fill") - .resizable() - .foregroundStyle(.gray200) - .frame(width: 28, height: 20) // 크기 지정 - .rotationEffect( - Angle(degrees: { - switch bubbleDirection { - case .left: - return 90 - case .right: - return 270 - case .bottom: - return 0 - } - }()) - ) - .offset( - x: { - switch bubbleDirection { - case .left: - return (min(textWidth, maxBubbleWidth) / 2) + 1 - case .right: - return -(min(textWidth, maxBubbleWidth) / 2) - 1 - case .bottom: - return 0 - } - }(), - y: bubbleDirection == .bottom ? -(min(textHeight, maxBubbleHeight) / 2) - 2 : 0 // 높이의 반만큼 화살표 위로 이동 - ) - - ScrollView() { - VStack { - Text(targetText) - .font(.system(size: 14, weight: .regular)) - .foregroundColor(.point2) - .lineSpacing(3) - .padding(.vertical, 14) - .padding(.horizontal, 18) - .background( - GeometryReader { textGeometry in - Color.clear - .preference(key: ViewHeightKey.self, value: textGeometry.size.height) - } - ) - } - .frame(maxWidth: maxBubbleWidth) // maxBubbleWidth로 최대 너비 설정 - } - .frame(width: min(textWidth, maxBubbleWidth), height: min(textHeight, maxBubbleHeight)) - } - } - } - .onAppear { - bubblePositionForScreen(translatePosition, in: geometry.size) - textWidth = translatePosition.width * 1.5 // 글자 수 적을 때 너비 여유롭게 - triggerTranslation() - } - .position(updatedBubblePosition) - .onChange(of: selectedText) { - isTranslationComplete = false // 번역 완료 되었을 때 뷰 다시 그리게 false 처리 - bubblePositionForScreen(translatePosition, in: geometry.size) - textWidth = translatePosition.width * 1.5 - triggerTranslation() - } - .onPreferenceChange(ViewHeightKey.self) { height in - textHeight = height - } - .translationTask(configuration) { session in - do { - let cleanedText = removeHyphen(in: selectedText) - let response = try await session.translate(cleanedText) - targetText = response.targetText - if !targetText.isEmpty { - isTranslationComplete = true - } - } catch { - print(" 번역 중 에러 발생 ") - } - } - - } - } - - // 번역 - private func triggerTranslation() { - guard configuration == nil else { - configuration?.invalidate() - return - } - - // 현재 언어는 영어 -> 한국어로 고정 - configuration = .init(source: Locale.Language(identifier: "en"), - target: Locale.Language(identifier: "ko")) - } - - // TranslateView 위치 조정하는 함수 - private func bubblePositionForScreen(_ rect: CGRect, in screenSize: CGSize) { - if floatingViewModel.splitMode { // 스플릿 뷰 켜져 있으면 항상 아래에 붙게 - // 말풍선이 선택 영역 아래에 붙음 - bubbleDirection = .bottom - if isPaperViewFirst { - updatedBubblePosition = CGPoint(x: rect.midX, y: rect.maxY + rect.height/3) - } else { // 스플릿 뷰에서 논문이 오른쪽에 붙으면 스크린의 반만큼 왼쪽으로 이동시킴 - updatedBubblePosition = CGPoint(x: rect.midX - (screenSize.width), y: rect.maxY + rect.height/3) - } - } else if rect.width > (screenSize.width / 2) { // 선택 영역이 차지하는 범위가 1/2 이상이면 - // 말풍선이 선택 영역 아래에 붙음 - bubbleDirection = .bottom - updatedBubblePosition = CGPoint(x: rect.midX, y: rect.maxY) - } else if rect.maxX > (screenSize.width / 2) && rect.minX > (screenSize.width / 3) { - // 말풍선이 선택 영역 왼쪽에 붙음 - bubbleDirection = .left - updatedBubblePosition = CGPoint(x: rect.minX - maxBubbleWidth + 150, y: rect.midY - 100) - } else if rect.maxX < (screenSize.width / 2) && rect.minX < (screenSize.width / 3){ - // 말풍선이 선택 영역 오른쪽에 붙음 - bubbleDirection = .right - updatedBubblePosition = CGPoint(x: rect.maxX + maxBubbleWidth - 150, y: rect.midY - 100) - } else { - // 말풍선이 선택 영역 아래에 붙음 - bubbleDirection = .bottom - updatedBubblePosition = CGPoint(x: rect.midX, y: rect.maxY + rect.height/3) - } - return - } - - // 줄바꿈 전에 있는 '-'를 제거하는 함수 - func removeHyphen(in text: String) -> String { - var result = "" - let lines = text.split(separator: "\n", omittingEmptySubsequences: false) - - for line in lines { - if line.hasSuffix("-") { - result += line.dropLast() // 줄 끝 '-'를 제거하고 줄바꿈 추가 - } else { - result += line + "\n" // '-'가 없는 줄은 그대로 추가 - } - } - return result.trimmingCharacters(in: .whitespacesAndNewlines) - } -} - -// 텍스트 높이 계산에 사용할 PreferenceKey -private struct ViewHeightKey: PreferenceKey { - static var defaultValue: CGFloat = 0 - static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { - value = max(value, nextValue()) - } -} diff --git a/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift b/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift index 84890394..241abd4b 100644 --- a/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift +++ b/Project/Reazy/Views/PDF/PDFViewer/OriginalView.swift @@ -33,16 +33,11 @@ struct OriginalView: View { viewModel.setHighlight(selectedComments: viewModel.selectedComments, isTapped: viewModel.isCommentTapped) } } - .onTapGesture { - // 터치 시 말풍선 뷰를 숨기는 처리 추가 - viewModel.updateTranslateView(selectedText: "", translateBubblePosition: .zero) - } // 번역에 사용되는 말풍선뷰 if viewModel.toolMode == .translate { if #available(iOS 18.0, *) { if viewModel.isTranslateViewVisible { - TranslateView(selectedText: $viewModel.selectedText, translatePosition: $viewModel.translateViewPosition, isPaperViewFirst: $viewModel.isPaperViewFirst) - .environmentObject(floatingViewModel) + TranslateView(selectedText: $viewModel.selectedText, translatePosition: $viewModel.translateViewPosition) .environmentObject(viewModel) } } diff --git a/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift b/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift index fd937444..b9445cf6 100644 --- a/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift +++ b/Project/Reazy/Views/PDF/PDFViewer/VC/OriginalViewController.swift @@ -178,7 +178,7 @@ extension OriginalViewController { guard let selection = self.mainPDFView.currentSelection else { // 선택된 텍스트가 없을 때 특정 액션 self.viewModel.selectedText = "" // 선택된 텍스트 초기화 - self.viewModel.translateViewVisible = false // 말풍선 뷰 숨김 + self.viewModel.translateViewVisible = true // 말풍선 뷰 숨김 return } diff --git a/Project/Reazy/Views/PDF/TranslateView.swift b/Project/Reazy/Views/PDF/TranslateView.swift new file mode 100644 index 00000000..b8cfa6d0 --- /dev/null +++ b/Project/Reazy/Views/PDF/TranslateView.swift @@ -0,0 +1,134 @@ +// +// TranslateView.swift +// Reazy +// +// Created by Minjung Lee on 10/31/24. +// + +import SwiftUI +import Translation + +@available(iOS 18.0, *) +struct TranslateView: View { + @EnvironmentObject var viewModel: MainPDFViewModel + + @Binding var selectedText: String + @Binding var translatePosition: CGRect + + @State private var targetText = "" // 번역 결과 텍스트 + @State private var configuration: TranslationSession.Configuration? + + @State private var maxBubbleWidth: CGFloat = 400 // bubble 최대 너비 + @State private var maxBubbleHeight: CGFloat = 280 // bubble 최대 높이 + + @State private var textHeight: CGFloat = 30 // 텍스트 높이 저장 + + @State private var isPopoverVisible: Bool = false + @State private var updatedBubblePosition: CGPoint = .zero // 조정된 bubble view 위치 + @State private var isTranslationComplete: Bool = false // 번역 완료 되었는지 확인해 뷰 새로 그리기 위한 flag + + var body: some View { + GeometryReader { geometry in + Color.clear + .foregroundStyle(.gray200) + .popover(isPresented: $isPopoverVisible, arrowEdge: .bottom) { + ZStack(alignment: .center) { + ScrollView { + Text(targetText) + .foregroundColor(.point2) + .lineSpacing(8) + .padding(.vertical, 14) + .padding(.horizontal, 16) + .font(.system(size: 16, weight: .regular)) + .frame(maxWidth: maxBubbleWidth, alignment: .leading) + .background( + GeometryReader { textGeometry in + Color.clear + .preference(key: ViewHeightKey.self, value: textGeometry.size.height) + } + ) + } + .padding(.vertical, 14) + .padding(.horizontal, 16) + .frame(height: min(textHeight, maxBubbleHeight)) + .frame(maxWidth: maxBubbleWidth, maxHeight: maxBubbleHeight) // ScrollView 높이 제한 + .onPreferenceChange(ViewHeightKey.self) { height in + DispatchQueue.main.async { + textHeight = height + } + } + } + } + .frame(maxHeight: maxBubbleHeight) + .position(updatedBubblePosition) + .translationTask(configuration) { session in + do { + let cleanedText = removeHyphen(in: selectedText) + let response = try await session.translate(cleanedText) + targetText = response.targetText + if !targetText.isEmpty { + isTranslationComplete = true + isPopoverVisible = true + } + } catch { + print(" 번역 중 에러 발생 ") + } + } + .onAppear { + bubblePositionForScreen(translatePosition, in: geometry.size) + triggerTranslation() + } + .onChange(of: selectedText) { + isTranslationComplete = false + bubblePositionForScreen(translatePosition, in: geometry.size) + triggerTranslation() + } + .onChange(of: isTranslationComplete) { + if isTranslationComplete { + isPopoverVisible = true + } + } + } + } + + // 번역 + private func triggerTranslation() { + guard configuration == nil else { + configuration?.invalidate() + return + } + + // 현재 언어는 영어 -> 한국어로 고정 + configuration = .init(source: Locale.Language(identifier: "en"), + target: Locale.Language(identifier: "ko")) + } + + // TranslateView 위치 조정하는 함수 + private func bubblePositionForScreen(_ rect: CGRect, in screenSize: CGSize) { + updatedBubblePosition = CGPoint(x: rect.midX, y: rect.minY) + return + } + + // 줄바꿈 전에 있는 '-'를 제거하는 함수 + func removeHyphen(in text: String) -> String { + var result = "" + let lines = text.split(separator: "\n", omittingEmptySubsequences: false) + + for line in lines { + if line.hasSuffix("-") { + result += line + } else { + result += line + } + } + return result.trimmingCharacters(in: .whitespacesAndNewlines) + } +} + +// 텍스트 높이 계산에 사용할 PreferenceKey +private struct ViewHeightKey: PreferenceKey { + static var defaultValue: CGFloat = 0 + static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { + value = max(value, nextValue()) + } +} diff --git a/Project/Reazy/Views/PDF/BubbleViewOlderVer.swift b/Project/Reazy/Views/PDF/TranslateViewOlderVer.swift similarity index 100% rename from Project/Reazy/Views/PDF/BubbleViewOlderVer.swift rename to Project/Reazy/Views/PDF/TranslateViewOlderVer.swift From fdbd8e2e02a38e31431f754fc32dfc28022257cb Mon Sep 17 00:00:00 2001 From: minjung0067 Date: Fri, 15 Nov 2024 17:38:06 +0900 Subject: [PATCH 10/15] =?UTF-8?q?[#200]=20=EC=97=B0=ED=95=84=20=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=EC=A6=88=20=EC=96=87=EA=B2=8C=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Project/Reazy/Views/PDF/Drawing/PDFDrawer.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project/Reazy/Views/PDF/Drawing/PDFDrawer.swift b/Project/Reazy/Views/PDF/Drawing/PDFDrawer.swift index dcc1b194..9d67dcd4 100644 --- a/Project/Reazy/Views/PDF/Drawing/PDFDrawer.swift +++ b/Project/Reazy/Views/PDF/Drawing/PDFDrawer.swift @@ -16,7 +16,7 @@ enum DrawingTool: Int { var width: CGFloat { switch self { case .eraser: return 5 - case .pencil: return 1 + case .pencil: return 0.5 default: return 0 } } From 51e7264c2b574c868819199787e2488431e8f0e0 Mon Sep 17 00:00:00 2001 From: wltnryu Date: Fri, 15 Nov 2024 17:39:34 +0900 Subject: [PATCH 11/15] =?UTF-8?q?[#205]=20=EC=99=84=EB=A3=8C=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Project/Reazy/Views/Home/HomeView.swift | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Project/Reazy/Views/Home/HomeView.swift b/Project/Reazy/Views/Home/HomeView.swift index 148058a0..f460784d 100644 --- a/Project/Reazy/Views/Home/HomeView.swift +++ b/Project/Reazy/Views/Home/HomeView.swift @@ -338,16 +338,14 @@ private struct RenamePaperTitleView: View { } } label: { Image(systemName: "xmark") - .resizable() - .scaledToFit() - .frame(width: 17) + .font(.system(size: 18)) } .foregroundStyle(.gray100) .padding(28) Spacer() - Button("완료") { + Button(action: { if isEditingTitle { pdfFileManager.updateTitle(at: paperInfo.id, title: text) isEditingTitle = false @@ -356,9 +354,16 @@ private struct RenamePaperTitleView: View { self.pdfFileManager.memoText = text isEditingMemo = false } + }) { + RoundedRectangle(cornerRadius: 20) + .stroke(.gray100, lineWidth: 1) + .frame(width: 68, height: 36) + .overlay( + Text("완료") + .reazyFont(.button1) + .foregroundStyle(.gray100) + ) } - .reazyFont(.button1) - .foregroundStyle(.gray100) .padding(28) } From e94def5b3231a5eebf7b36c17bec2677361ce699 Mon Sep 17 00:00:00 2001 From: minjung0067 Date: Fri, 15 Nov 2024 17:40:31 +0900 Subject: [PATCH 12/15] =?UTF-8?q?[#200]=20zstack=20=EA=B8=B0=EC=A4=80=20to?= =?UTF-8?q?p=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Project/Reazy/Views/PDF/TranslateView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project/Reazy/Views/PDF/TranslateView.swift b/Project/Reazy/Views/PDF/TranslateView.swift index b8cfa6d0..0350e91c 100644 --- a/Project/Reazy/Views/PDF/TranslateView.swift +++ b/Project/Reazy/Views/PDF/TranslateView.swift @@ -32,7 +32,7 @@ struct TranslateView: View { Color.clear .foregroundStyle(.gray200) .popover(isPresented: $isPopoverVisible, arrowEdge: .bottom) { - ZStack(alignment: .center) { + ZStack(alignment: .top) { ScrollView { Text(targetText) .foregroundColor(.point2) From 3106692534a174c8853098312ed8a5bd33b77c94 Mon Sep 17 00:00:00 2001 From: wltnryu Date: Sat, 16 Nov 2024 12:50:43 +0900 Subject: [PATCH 13/15] =?UTF-8?q?[#205]=20homeView=20=EC=A0=9C=EB=AA=A9=20?= =?UTF-8?q?=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=99=BC=EC=AA=BD=20=EC=A0=95?= =?UTF-8?q?=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Reazy/Views/Home/Paper/PaperInfoView.swift | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Project/Reazy/Views/Home/Paper/PaperInfoView.swift b/Project/Reazy/Views/Home/Paper/PaperInfoView.swift index df7c734e..7479b1bd 100644 --- a/Project/Reazy/Views/Home/Paper/PaperInfoView.swift +++ b/Project/Reazy/Views/Home/Paper/PaperInfoView.swift @@ -33,12 +33,15 @@ struct PaperInfoView: View { .scaledToFit() .padding(.horizontal, 30) - Text(title) - .reazyFont(.text1) - .foregroundStyle(.gray900) - .padding(.horizontal, 30) - .padding(.top, 14) - .lineLimit(2) + HStack(spacing: 0) { + Text(title) + .reazyFont(.text1) + .foregroundStyle(.gray900) + .padding(.horizontal, 30) + .padding(.top, 14) + .lineLimit(2) + Spacer() + } HStack(spacing: 0) { Menu { From cd52d0591d0bc9bf631ed6e9891458d6b57cf20e Mon Sep 17 00:00:00 2001 From: minjung0067 Date: Sat, 16 Nov 2024 16:13:17 +0900 Subject: [PATCH 14/15] =?UTF-8?q?[#200]=20=EC=8A=A4=ED=81=AC=EB=A1=A4?= =?UTF-8?q?=EB=B0=94=20=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20=20padding=20?= =?UTF-8?q?=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Project/Reazy/Views/PDF/TranslateView.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Project/Reazy/Views/PDF/TranslateView.swift b/Project/Reazy/Views/PDF/TranslateView.swift index 0350e91c..f408212a 100644 --- a/Project/Reazy/Views/PDF/TranslateView.swift +++ b/Project/Reazy/Views/PDF/TranslateView.swift @@ -33,12 +33,11 @@ struct TranslateView: View { .foregroundStyle(.gray200) .popover(isPresented: $isPopoverVisible, arrowEdge: .bottom) { ZStack(alignment: .top) { - ScrollView { + ScrollView(showsIndicators: false) { Text(targetText) .foregroundColor(.point2) .lineSpacing(8) .padding(.vertical, 14) - .padding(.horizontal, 16) .font(.system(size: 16, weight: .regular)) .frame(maxWidth: maxBubbleWidth, alignment: .leading) .background( @@ -48,7 +47,7 @@ struct TranslateView: View { } ) } - .padding(.vertical, 14) + .padding(.bottom, 14) .padding(.horizontal, 16) .frame(height: min(textHeight, maxBubbleHeight)) .frame(maxWidth: maxBubbleWidth, maxHeight: maxBubbleHeight) // ScrollView 높이 제한 From 9b0c74904501259bfd0df8bd1a849587cf602584 Mon Sep 17 00:00:00 2001 From: minjung0067 Date: Sat, 16 Nov 2024 16:28:46 +0900 Subject: [PATCH 15/15] =?UTF-8?q?[#200]=20=EB=B2=84=EC=A0=84=201.0.1?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Reazy.xcodeproj/project.pbxproj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Reazy.xcodeproj/project.pbxproj b/Reazy.xcodeproj/project.pbxproj index 0b8a28c1..0dfa2785 100644 --- a/Reazy.xcodeproj/project.pbxproj +++ b/Reazy.xcodeproj/project.pbxproj @@ -381,6 +381,8 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "Reazy-Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = Reazy; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -392,7 +394,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.chillin.reazy; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -417,6 +419,8 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "Reazy-Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = Reazy; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -428,7 +432,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.chillin.reazy; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";