103 lines
3.3 KiB
Swift
103 lines
3.3 KiB
Swift
import Foundation
|
|
import PDFKit
|
|
import UIKit
|
|
|
|
@objc(SecurePdfViewerComponentView)
|
|
public class SecurePdfViewerComponentView: UIView, UIGestureRecognizerDelegate {
|
|
let attemptStore = PasswordAttemptStore()
|
|
let pdfView = SecurePDFView()
|
|
var pdfDocument: PDFDocument?
|
|
var linkDelegate: PDFViewLinkDelegate?
|
|
var normalizedSource: String = ""
|
|
var pageIndicator: PageIndicatorView?
|
|
|
|
var lastLayoutWidth: CGFloat = 0
|
|
var thumbnailLayoutMode: ThumbnailLayoutMode!
|
|
var customThumbnailView: CustomThumbnailView!
|
|
var thumbnailLeadingConstraint: NSLayoutConstraint!
|
|
var thumbnailWidthConstraint: NSLayoutConstraint!
|
|
var thumbnailHeightConstraint: NSLayoutConstraint?
|
|
var thumbnailTopConstraint: NSLayoutConstraint!
|
|
var thumbnailBottomConstraint: NSLayoutConstraint!
|
|
var pdfViewLeadingConstraint: NSLayoutConstraint!
|
|
var pageIndicatorLeadingConstraint: NSLayoutConstraint!
|
|
|
|
// Enum for thumbnail display mode
|
|
enum ThumbnailLayoutMode {
|
|
case panel // Side by side with PDF (iPad/wide screens)
|
|
case drawer // Slides over the PDF (iPhone/narrow screens)
|
|
}
|
|
|
|
// UI interaction properties
|
|
var contentOffsetObservation: NSKeyValueObservation?
|
|
var singleTapRecognizer: UITapGestureRecognizer!
|
|
var doubleTapRecognizer: UITapGestureRecognizer!
|
|
var hideTimer: Timer?
|
|
|
|
@objc var source: NSString = "" {
|
|
didSet {
|
|
let rawPath = source as String
|
|
if rawPath.hasPrefix("file://"), let url = URL(string: rawPath), url.isFileURL {
|
|
normalizedSource = url.path
|
|
} else {
|
|
normalizedSource = rawPath
|
|
}
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
|
self.loadPDF()
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc var password: NSString? {
|
|
didSet {
|
|
if !normalizedSource.isEmpty && password != nil {
|
|
attemptUnlockIfNeeded()
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc var allowLinks: Bool = true
|
|
@objc var onLinkPressed: RCTDirectEventBlock?
|
|
@objc var onLinkPressedDisabled: RCTDirectEventBlock?
|
|
@objc var onLoad: RCTDirectEventBlock?
|
|
@objc var onPasswordRequired: RCTDirectEventBlock?
|
|
@objc var onPasswordFailed: RCTDirectEventBlock?
|
|
@objc var onPasswordFailureLimitReached: RCTDirectEventBlock?
|
|
@objc var onLoadError: RCTDirectEventBlock?
|
|
@objc var onTap: RCTDirectEventBlock?
|
|
|
|
@objc public override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
setupPDFView()
|
|
}
|
|
|
|
@objc public required init?(coder: NSCoder) {
|
|
super.init(coder: coder)
|
|
setupPDFView()
|
|
}
|
|
|
|
public override func layoutSubviews() {
|
|
super.layoutSubviews()
|
|
|
|
// Check if we need to change layout mode when the view resizes
|
|
layoutThumbnailsBasedOnWidth()
|
|
}
|
|
}
|
|
|
|
class PDFViewLinkDelegate: NSObject, PDFViewDelegate {
|
|
weak var owner: SecurePdfViewerComponentView?
|
|
|
|
init(owner: SecurePdfViewerComponentView?) {
|
|
self.owner = owner
|
|
}
|
|
|
|
@objc func pdfViewWillClick(onLink sender: PDFView, with url: URL) {
|
|
guard let owner = owner else { return }
|
|
|
|
if owner.allowLinks {
|
|
owner.onLinkPressed?(["url": url.absoluteString])
|
|
} else {
|
|
owner.onLinkPressedDisabled?([:])
|
|
}
|
|
}
|
|
}
|