Quellcode durchsuchen

Fix scanner, premium access, and import edge cases.

Prevent stale premium cache bypass, grayscale band corruption, partial scan files, duplicate bookmarks, stacked overlays, and gate scan file import separately.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 vor 3 Wochen
Ursprung
Commit
0c4c45dfb6

+ 16 - 4
smart_printer/ImportedFilesStore.swift

@@ -31,9 +31,18 @@ enum ImportedFilesStore {
         guard AppSettings.saveRecentFiles else { return urls.count }
 
         var bookmarks = defaults.array(forKey: bookmarksKey) as? [Data] ?? []
+        var existingPaths = Set(
+            bookmarks.compactMap { data -> String? in
+                guard case .valid(let url) = resolveBookmarkData(data) else { return nil }
+                return normalizedPath(for: url)
+            }
+        )
         var added = 0
 
         for url in urls {
+            let path = normalizedPath(for: url)
+            guard !existingPaths.contains(path) else { continue }
+
             let accessed = url.startAccessingSecurityScopedResource()
             defer {
                 if accessed { url.stopAccessingSecurityScopedResource() }
@@ -45,16 +54,19 @@ enum ImportedFilesStore {
                 relativeTo: nil
             ) else { continue }
 
-            if !bookmarks.contains(bookmark) {
-                bookmarks.append(bookmark)
-                added += 1
-            }
+            bookmarks.append(bookmark)
+            existingPaths.insert(path)
+            added += 1
         }
 
         defaults.set(bookmarks, forKey: bookmarksKey)
         return added
     }
 
+    private static func normalizedPath(for url: URL) -> String {
+        url.standardizedFileURL.path
+    }
+
     private enum BookmarkResolution {
         case valid(URL)
         case stale

+ 1 - 1
smart_printer/PaywallView.swift

@@ -456,7 +456,7 @@ enum PremiumAccess {
     static func canAccess(_ feature: AppFeature) -> Bool {
         let store = StoreManager.shared
         if store.isResolvingEntitlements {
-            return store.isPremium || FreeTierManager.canAccess(feature, isPremium: false)
+            return FreeTierManager.canAccess(feature, isPremium: false)
         }
         return FreeTierManager.canAccess(feature, isPremium: store.isPremium)
     }

+ 1 - 0
smart_printer/ScanFileView.swift

@@ -46,6 +46,7 @@ enum ScanFileService {
         case .scanner:
             startScannerScan(from: window)
         case .importFile:
+            guard PremiumAccess.require(feature: .scanImport, from: window) else { return }
             importFile(from: window)
         }
     }

+ 24 - 11
smart_printer/ScannerService.swift

@@ -586,9 +586,6 @@ extension ScannerService: ICDeviceDelegate, ICScannerDeviceDelegate {
     nonisolated func scannerDevice(_ scanner: ICScannerDevice, didScanTo url: URL) {
         Task { @MainActor in
             scannedImageURL = url
-            if let image = imageFromScanURL(url) {
-                finishScan(with: .success(image))
-            }
         }
     }
 
@@ -649,14 +646,31 @@ private extension ScanResolution {
 }
 
 private extension ScannerService {
+    struct BandImageFormat {
+        let colorSpace: CGColorSpace
+        let bitmapInfo: CGBitmapInfo
+    }
+
+    func bandImageFormat(for bandData: ICScannerBandData) -> BandImageFormat {
+        if Int(bandData.bitsPerPixel) <= 8 {
+            return BandImageFormat(
+                colorSpace: CGColorSpaceCreateDeviceGray(),
+                bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue)
+            )
+        }
+        return BandImageFormat(
+            colorSpace: CGColorSpaceCreateDeviceRGB(),
+            bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipLast.rawValue)
+        )
+    }
+
     func imageFromBandData(_ bandData: ICScannerBandData) -> NSImage? {
         guard let data = bandData.dataBuffer,
               !data.isEmpty,
               bandData.fullImageWidth > 0,
               bandData.dataNumRows > 0 else { return nil }
 
-        let colorSpace = CGColorSpaceCreateDeviceRGB()
-        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipLast.rawValue)
+        let format = bandImageFormat(for: bandData)
         guard let provider = CGDataProvider(data: data as CFData),
               let cgImage = CGImage(
                   width: Int(bandData.fullImageWidth),
@@ -664,8 +678,8 @@ private extension ScannerService {
                   bitsPerComponent: Int(bandData.bitsPerComponent),
                   bitsPerPixel: Int(bandData.bitsPerPixel),
                   bytesPerRow: Int(bandData.bytesPerRow),
-                  space: colorSpace,
-                  bitmapInfo: bitmapInfo,
+                  space: format.colorSpace,
+                  bitmapInfo: format.bitmapInfo,
                   provider: provider,
                   decode: nil,
                   shouldInterpolate: true,
@@ -700,8 +714,7 @@ private extension ScannerService {
             fullData.replaceSubrange(startOffset..<(startOffset + copyLength), with: bandData.prefix(copyLength))
         }
 
-        let colorSpace = CGColorSpaceCreateDeviceRGB()
-        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipLast.rawValue)
+        let format = bandImageFormat(for: first)
         var mutableData = fullData
         return mutableData.withUnsafeMutableBytes { buffer in
             guard let baseAddress = buffer.baseAddress,
@@ -711,8 +724,8 @@ private extension ScannerService {
                       height: height,
                       bitsPerComponent: Int(first.bitsPerComponent),
                       bytesPerRow: bytesPerRow,
-                      space: colorSpace,
-                      bitmapInfo: bitmapInfo.rawValue
+                      space: format.colorSpace,
+                      bitmapInfo: format.bitmapInfo.rawValue
                   ),
                   let cgImage = context.makeImage() else {
                 return nil

+ 6 - 0
smart_printer/ViewController.swift

@@ -298,6 +298,9 @@ class ViewController: NSViewController {
         guard guardPremiumFeature(.photoPreview) else { return }
         photoPreviewOverlay?.dismiss(animated: false)
         filePreviewOverlay?.dismiss(animated: false)
+        printTextOverlay?.dismiss(animated: false)
+        printContactsOverlay?.dismiss(animated: false)
+        drawPrintOverlay?.dismiss(animated: false)
         ocrFileOverlay?.dismiss(animated: false)
         scanFileOverlay?.dismiss(animated: false)
         dismissScannerOverlay()
@@ -317,6 +320,9 @@ class ViewController: NSViewController {
         guard guardPremiumFeature(.filePreview) else { return }
         photoPreviewOverlay?.dismiss(animated: false)
         filePreviewOverlay?.dismiss(animated: false)
+        printTextOverlay?.dismiss(animated: false)
+        printContactsOverlay?.dismiss(animated: false)
+        drawPrintOverlay?.dismiss(animated: false)
         ocrFileOverlay?.dismiss(animated: false)
         scanFileOverlay?.dismiss(animated: false)
         dismissScannerOverlay()