|
@@ -26,6 +26,7 @@ class ViewController: NSViewController {
|
|
|
private var scanFileOverlay: ScanFileOverlayView?
|
|
private var scanFileOverlay: ScanFileOverlayView?
|
|
|
private var scannerOverlay: ScannerOverlayView?
|
|
private var scannerOverlay: ScannerOverlayView?
|
|
|
private var scannerDidComplete = false
|
|
private var scannerDidComplete = false
|
|
|
|
|
+ private var didRecordFreeScanThisSession = false
|
|
|
|
|
|
|
|
private var headerView: NSView!
|
|
private var headerView: NSView!
|
|
|
private var contentTopBelowHeader: NSLayoutConstraint!
|
|
private var contentTopBelowHeader: NSLayoutConstraint!
|
|
@@ -115,7 +116,7 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func presentScanner(showScanPreview: Bool = false, onComplete: @escaping (Result<NSImage, Error>) -> Void) {
|
|
func presentScanner(showScanPreview: Bool = false, onComplete: @escaping (Result<NSImage, Error>) -> Void) {
|
|
|
- guard guardPremiumFeature() else { return }
|
|
|
|
|
|
|
+ guard guardPremiumFeature(.scannerScan) else { return }
|
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
|
printTextOverlay?.dismiss(animated: false)
|
|
printTextOverlay?.dismiss(animated: false)
|
|
@@ -125,6 +126,7 @@ class ViewController: NSViewController {
|
|
|
scanFileOverlay?.dismiss(animated: false)
|
|
scanFileOverlay?.dismiss(animated: false)
|
|
|
|
|
|
|
|
scannerDidComplete = false
|
|
scannerDidComplete = false
|
|
|
|
|
+ didRecordFreeScanThisSession = false
|
|
|
|
|
|
|
|
if let existing = scannerOverlay, existing.superview != nil {
|
|
if let existing = scannerOverlay, existing.superview != nil {
|
|
|
configureScannerOverlay(existing, showScanPreview: showScanPreview, onComplete: onComplete)
|
|
configureScannerOverlay(existing, showScanPreview: showScanPreview, onComplete: onComplete)
|
|
@@ -155,7 +157,8 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
overlay.onScanComplete = { [weak self] image in
|
|
overlay.onScanComplete = { [weak self] image in
|
|
|
- Task { @MainActor in
|
|
|
|
|
|
|
+ Task { @MainActor [weak self] in
|
|
|
|
|
+ guard let self else { return }
|
|
|
let processed: NSImage
|
|
let processed: NSImage
|
|
|
if let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) {
|
|
if let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) {
|
|
|
processed = await ScanDocumentProcessor.process(cgImage) ?? image
|
|
processed = await ScanDocumentProcessor.process(cgImage) ?? image
|
|
@@ -165,9 +168,18 @@ class ViewController: NSViewController {
|
|
|
|
|
|
|
|
let displayImage = processed.normalizedForDisplay()
|
|
let displayImage = processed.normalizedForDisplay()
|
|
|
if showScanPreview {
|
|
if showScanPreview {
|
|
|
|
|
+ if !self.didRecordFreeScanThisSession {
|
|
|
|
|
+ FreeTierManager.recordScannerScanIfNeeded(
|
|
|
|
|
+ isPremium: StoreManager.shared.isPremium
|
|
|
|
|
+ )
|
|
|
|
|
+ self.didRecordFreeScanThisSession = true
|
|
|
|
|
+ }
|
|
|
overlay.updateScanPreview(displayImage)
|
|
overlay.updateScanPreview(displayImage)
|
|
|
} else {
|
|
} else {
|
|
|
- self?.scannerDidComplete = true
|
|
|
|
|
|
|
+ self.scannerDidComplete = true
|
|
|
|
|
+ FreeTierManager.recordScannerScanIfNeeded(
|
|
|
|
|
+ isPremium: StoreManager.shared.isPremium
|
|
|
|
|
+ )
|
|
|
onComplete(.success(displayImage))
|
|
onComplete(.success(displayImage))
|
|
|
overlay.dismiss()
|
|
overlay.dismiss()
|
|
|
}
|
|
}
|
|
@@ -176,7 +188,7 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func presentPrintText() {
|
|
func presentPrintText() {
|
|
|
- guard guardPremiumFeature() else { return }
|
|
|
|
|
|
|
+ guard guardPremiumFeature(.printText) else { return }
|
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
|
printContactsOverlay?.dismiss(animated: false)
|
|
printContactsOverlay?.dismiss(animated: false)
|
|
@@ -194,7 +206,7 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func presentPrintContacts() {
|
|
func presentPrintContacts() {
|
|
|
- guard guardPremiumFeature() else { return }
|
|
|
|
|
|
|
+ guard guardPremiumFeature(.printContacts) else { return }
|
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
|
printTextOverlay?.dismiss(animated: false)
|
|
printTextOverlay?.dismiss(animated: false)
|
|
@@ -220,7 +232,7 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func presentOCRFile(imageURL: URL) {
|
|
func presentOCRFile(imageURL: URL) {
|
|
|
- guard guardPremiumFeature() else { return }
|
|
|
|
|
|
|
+ guard guardPremiumFeature(.ocrFile) else { return }
|
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
|
printTextOverlay?.dismiss(animated: false)
|
|
printTextOverlay?.dismiss(animated: false)
|
|
@@ -238,7 +250,6 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func presentScanFile(pages: [ScanPage]) {
|
|
func presentScanFile(pages: [ScanPage]) {
|
|
|
- guard guardPremiumFeature() else { return }
|
|
|
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
|
printTextOverlay?.dismiss(animated: false)
|
|
printTextOverlay?.dismiss(animated: false)
|
|
@@ -265,7 +276,7 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func presentDrawPrint() {
|
|
func presentDrawPrint() {
|
|
|
- guard guardPremiumFeature() else { return }
|
|
|
|
|
|
|
+ guard guardPremiumFeature(.drawPrint) else { return }
|
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
|
printTextOverlay?.dismiss(animated: false)
|
|
printTextOverlay?.dismiss(animated: false)
|
|
@@ -283,7 +294,7 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func presentPhotoPreview(urls: [URL]) {
|
|
func presentPhotoPreview(urls: [URL]) {
|
|
|
- guard guardPremiumFeature() else { return }
|
|
|
|
|
|
|
+ guard guardPremiumFeature(.photoPreview) else { return }
|
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
|
ocrFileOverlay?.dismiss(animated: false)
|
|
ocrFileOverlay?.dismiss(animated: false)
|
|
@@ -302,7 +313,7 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func presentFilePreview(urls: [URL]) {
|
|
func presentFilePreview(urls: [URL]) {
|
|
|
- guard guardPremiumFeature() else { return }
|
|
|
|
|
|
|
+ guard guardPremiumFeature(.filePreview) else { return }
|
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
photoPreviewOverlay?.dismiss(animated: false)
|
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
filePreviewOverlay?.dismiss(animated: false)
|
|
|
ocrFileOverlay?.dismiss(animated: false)
|
|
ocrFileOverlay?.dismiss(animated: false)
|
|
@@ -455,11 +466,6 @@ class ViewController: NSViewController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func showDestinationAfterEntitlementCheck(_ destination: SidebarDestination) {
|
|
private func showDestinationAfterEntitlementCheck(_ destination: SidebarDestination) {
|
|
|
- if destination == .scan || destination == .print, !StoreManager.shared.isPremium {
|
|
|
|
|
- presentPaywall(returnToHomeOnDismiss: true)
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
dismissFeatureOverlays()
|
|
dismissFeatureOverlays()
|
|
|
contentContainer.isHidden = false
|
|
contentContainer.isHidden = false
|
|
|
|
|
|
|
@@ -475,7 +481,12 @@ class ViewController: NSViewController {
|
|
|
contentTopBelowWindow.isActive = isSettings
|
|
contentTopBelowWindow.isActive = isSettings
|
|
|
|
|
|
|
|
if destination == .scanAndHome {
|
|
if destination == .scanAndHome {
|
|
|
- presentPaywall(returnToHomeOnDismiss: true)
|
|
|
|
|
|
|
+ if StoreManager.shared.isPremium {
|
|
|
|
|
+ sidebar.select(.scan)
|
|
|
|
|
+ showDestinationAfterEntitlementCheck(.scan)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ presentPaywall(returnToHomeOnDismiss: true)
|
|
|
|
|
+ }
|
|
|
} else {
|
|
} else {
|
|
|
dismissPaywall()
|
|
dismissPaywall()
|
|
|
}
|
|
}
|
|
@@ -504,22 +515,8 @@ class ViewController: NSViewController {
|
|
|
paywallOverlay = overlay
|
|
paywallOverlay = overlay
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private func guardPremiumFeature() -> Bool {
|
|
|
|
|
- let store = StoreManager.shared
|
|
|
|
|
- if store.isResolvingEntitlements {
|
|
|
|
|
- Task { @MainActor in
|
|
|
|
|
- await store.ensureEntitlementsResolved()
|
|
|
|
|
- guard !store.isPremium else { return }
|
|
|
|
|
- self.presentPaywall(returnToHomeOnDismiss: false)
|
|
|
|
|
- }
|
|
|
|
|
- return false
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- guard store.isPremium else {
|
|
|
|
|
- presentPaywall(returnToHomeOnDismiss: false)
|
|
|
|
|
- return false
|
|
|
|
|
- }
|
|
|
|
|
- return true
|
|
|
|
|
|
|
+ private func guardPremiumFeature(_ feature: AppFeature) -> Bool {
|
|
|
|
|
+ PremiumAccess.require(feature: feature, from: view.window)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func dismissPaywall() {
|
|
private func dismissPaywall() {
|