mirror of
https://github.com/mattermost/mattermost-mobile.git
synced 2026-11-05 18:38:54 +00:00
* Expo-Router partial migration * Full migration to ExpoRouter * i18n * add tests * Merge branch 'main' into expo-router * align package-lock.json * i18n * feedback review * feedback review * android 16kb patch * Refactored emoji picker keyboard using a state machine * set android launch_screen in drawables instead of layout * no conditional hooks * remove duplicate call in test * address feedback * fix tests and address more feedback * small corrections * small corrections * small corrections * fix draft test * fix draft test 2 * remove navigateToScreen in draff test * fix nit in draft test * remove doc file * Feedback review * fix snapshots * improve test coverage * fix i18n * Upgrade t o RN 0.83, other dependencies and new architecture (#9737) * library hardware-keyboard android new arch support fix * library rnshare android new arch support fix * library rnutils android new arch support fix * library secure-pdf-viewer add new arch support * Enable new arch on iOS and Android * update emm and network client with new-arch * update intune to use new-arch * performance improvements * fix tests * fixes post input on new-arch * fix android emoji picker * remove doc * run tests in parallel * upgrade to React Native 0.83.9, Expo 55, React 19, and New Architecture Bumps core dependencies to their latest versions: - React Native 0.77.3 → 0.83.9 (New Architecture enabled) - React 18.3.1 → 19.2.5 - Expo SDK 52 → 55 - TypeScript 5.8.3 → 6.0.3 - Node.js 22.16.0 → 24.15.0 - react-native-reanimated 3.17.3 → 4.3.0 - Various other dependency upgrades Migrates iOS AppDelegate from Objective-C to Swift, updates Android build tooling and Gradle wrapper, refreshes all patches and font assets, and adapts app code, tests, and CI workflows throughout for API changes introduced by these upgrades. * remove unecessary dismissKeyboard in notifications * feedback review * update intune to use new-arch * update @mattermost deps * missing i18n string * additional fixes * update fastlane
117 lines
3.9 KiB
Swift
117 lines
3.9 KiB
Swift
import Foundation
|
|
import PDFKit
|
|
import UIKit
|
|
import React
|
|
|
|
@objc(SecurePdfViewerComponentView)
|
|
@objcMembers
|
|
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 public 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 public var password: NSString? {
|
|
didSet {
|
|
if !normalizedSource.isEmpty && password != nil {
|
|
attemptUnlockIfNeeded()
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc public var allowLinks: Bool = true
|
|
|
|
// Use closures instead of RCTDirectEventBlock to be architecture-agnostic
|
|
// Old architecture (Paper) will set these via RCTDirectEventBlock in the manager
|
|
// New architecture (Fabric) will set these directly from the C++ wrapper
|
|
@objc public var onLinkPressed: (([String: Any]) -> Void)?
|
|
@objc public var onLinkPressedDisabled: (([String: Any]) -> Void)?
|
|
@objc public var onLoad: (([String: Any]) -> Void)?
|
|
@objc public var onPasswordRequired: (([String: Any]) -> Void)?
|
|
@objc public var onPasswordFailed: (([String: Any]) -> Void)?
|
|
@objc public var onPasswordFailureLimitReached: (([String: Any]) -> Void)?
|
|
@objc public var onLoadError: (([String: Any]) -> Void)?
|
|
@objc public var onTap: (([String: Any]) -> Void)?
|
|
|
|
@objc public override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
setupPDFView()
|
|
}
|
|
|
|
@objc public required init?(coder: NSCoder) {
|
|
super.init(coder: coder)
|
|
setupPDFView()
|
|
}
|
|
|
|
deinit {
|
|
// Clean up observers and timers to prevent crashes
|
|
contentOffsetObservation?.invalidate()
|
|
hideTimer?.invalidate()
|
|
NotificationCenter.default.removeObserver(self)
|
|
}
|
|
|
|
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?([:])
|
|
}
|
|
}
|
|
}
|