mattermost-mobile/libraries/@mattermost/secure-pdf-viewer/ios/SecurePdfViewerComponent/SecurePdfViewerComponentView+PDFHandling.swift
2025-06-19 15:30:56 +08:00

157 lines
5.7 KiB
Swift

import PDFKit
extension SecurePdfViewerComponentView {
func loadPDF() {
let filePath = normalizedSource
let fileKey = HashUtils.hashOfFilePathOrId(filePath)
guard !attemptStore.hasExceededLimit(for: fileKey) else {
onPasswordFailureLimitReached?(["maxAttempts": attemptStore.maxAllowedAttempts])
return
}
guard isValidCachedFile(path: filePath) else {
onLoadError?(["message": "Invalid file path"])
return
}
let url = URL(fileURLWithPath: filePath)
if let error = PDFDiagnostics.diagnosePotentialLoadFailure(at: url) {
onLoadError?(["message": error.description])
return
}
if let document = PDFDocument(url: url) {
pdfDocument = document
if document.isEncrypted {
let passwordAttempts = attemptStore.getRemainingAttempts(for: fileKey)
onPasswordRequired!(["maxAttempts": attemptStore.maxAllowedAttempts, "remainingAttempts": passwordAttempts])
} else {
pdfView.document = document
customThumbnailView.pdfView = pdfView
updatePageIndicator()
if thumbnailLayoutMode == .panel {
customThumbnailView.isHidden = false
layoutIfNeeded()
}
onLoad?([:])
}
} else {
let error = PDFDiagnostics.diagnoseLoadFailure(at: url)
onLoadError?(["message": error.description])
}
}
func attemptUnlockIfNeeded() {
guard let password = password as String?, let document = pdfDocument else {
return
}
let fileKey = HashUtils.hashOfFilePathOrId(normalizedSource)
if document.unlock(withPassword: password) {
attemptStore.resetAttempts(for: fileKey)
pdfView.document = document
customThumbnailView.pdfView = pdfView
updatePageIndicator()
onLoad?([:])
} else {
let remaining = attemptStore.registerFailedAttempt(for: fileKey)
if remaining <= 0 {
onPasswordFailureLimitReached?(["maxAttempts": attemptStore.maxAllowedAttempts])
} else {
onPasswordFailed?(["remainingAttempts": remaining])
}
}
}
@objc func pageChanged() {
updatePageIndicator()
}
@objc func toggleThumbnails() {
switch thumbnailLayoutMode {
case .panel:
let isCurrentlyVisible = thumbnailLeadingConstraint.constant == 0
if isCurrentlyVisible {
thumbnailLeadingConstraint.constant = -thumbnailWidthConstraint.constant
pdfViewLeadingConstraint.constant = 0
UIView.animate(withDuration: 0.3) {
self.customThumbnailView.isHidden = true
self.layoutIfNeeded()
}
} else {
customThumbnailView.isHidden = false
thumbnailLeadingConstraint.constant = 0
pdfViewLeadingConstraint.constant = thumbnailWidthConstraint.constant
UIView.animate(withDuration: 0.3) {
self.layoutIfNeeded()
}
}
case .drawer:
let isDrawerOpen = thumbnailLeadingConstraint.constant == 0
thumbnailLeadingConstraint.constant = isDrawerOpen ? -thumbnailWidthConstraint.constant : 0
pageIndicatorLeadingConstraint.constant = isDrawerOpen ? 16 : thumbnailWidthConstraint.constant + 16
customThumbnailView.isHidden = isDrawerOpen
UIView.animate(withDuration: 0.3) {
self.layoutIfNeeded()
}
case .none: break // this is to make the switch exhaustive although this one here is not reachable
}
}
func updateScrollContentHeight(_ height: CGFloat) {
// Remove old height constraint if it exists
if let existingConstraint = thumbnailHeightConstraint {
existingConstraint.isActive = false
thumbnailHeightConstraint = nil
}
// Create and activate new height constraint
thumbnailHeightConstraint = customThumbnailView.heightAnchor.constraint(equalToConstant: height)
thumbnailHeightConstraint?.isActive = true
}
func updatePageIndicator() {
guard let doc = pdfView.document, let page = pdfView.currentPage else { return }
let pageIndex = doc.index(for: page) + 1
let totalPages = doc.pageCount
pageIndicator?.updatePage(current: pageIndex, total: totalPages)
pageIndicator?.setAlpha(1)
hidePageIndicator()
}
func updatePageIndicatorPosition() {
if thumbnailLayoutMode == .panel {
// Keep PageIndicator in a fixed position
pageIndicatorLeadingConstraint.constant = 16
} else if thumbnailLayoutMode == .drawer {
// Align PageIndicator with the drawer
let isDrawerOpen = thumbnailLeadingConstraint.constant == 0
pageIndicatorLeadingConstraint.constant = isDrawerOpen ? thumbnailWidthConstraint.constant + 16 : 16
}
UIView.animate(withDuration: 0.3) {
self.layoutIfNeeded()
}
}
func hidePageIndicator() {
hideTimer?.invalidate()
hideTimer = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { [weak self] _ in
UIView.animate(withDuration: 0.3) {
self?.pageIndicator?.setAlpha(0)
}
}
}
}