Showing
8 changed files
with
202 additions
and
77 deletions
| @@ -5,6 +5,7 @@ | @@ -5,6 +5,7 @@ | ||
| 5 | - Add imageFromAssetBundle and networkImage | 5 | - Add imageFromAssetBundle and networkImage |
| 6 | - Add Page orientation on PdfPreview | 6 | - Add Page orientation on PdfPreview |
| 7 | - Improve PrintJob object | 7 | - Improve PrintJob object |
| 8 | +- Implement dynamic layout on iOS and macOS | ||
| 8 | 9 | ||
| 9 | ## 5.0.0-nullsafety.1 | 10 | ## 5.0.0-nullsafety.1 |
| 10 | 11 |
| @@ -28,6 +28,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | @@ -28,6 +28,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | ||
| 28 | private var urlObservation: NSKeyValueObservation? | 28 | private var urlObservation: NSKeyValueObservation? |
| 29 | private var jobName: String? | 29 | private var jobName: String? |
| 30 | private var orientation: UIPrintInfo.Orientation? | 30 | private var orientation: UIPrintInfo.Orientation? |
| 31 | + private let semaphore = DispatchSemaphore(value: 0) | ||
| 31 | 32 | ||
| 32 | public init(printing: PrintingPlugin, index: Int) { | 33 | public init(printing: PrintingPlugin, index: Int) { |
| 33 | self.printing = printing | 34 | self.printing = printing |
| @@ -46,9 +47,9 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | @@ -46,9 +47,9 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | ||
| 46 | } | 47 | } |
| 47 | } | 48 | } |
| 48 | 49 | ||
| 49 | - func cancelJob(_ error: String?) { | 50 | + func cancelJob(_: String?) { |
| 50 | pdfDocument = nil | 51 | pdfDocument = nil |
| 51 | - printing.onCompleted(printJob: self, completed: false, error: error as NSString?) | 52 | + semaphore.signal() |
| 52 | } | 53 | } |
| 53 | 54 | ||
| 54 | func setDocument(_ data: Data?) { | 55 | func setDocument(_ data: Data?) { |
| @@ -57,24 +58,25 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | @@ -57,24 +58,25 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | ||
| 57 | let dataProvider = CGDataProvider(dataInfo: nil, data: bytesPointer, size: data?.count ?? 0, releaseData: dataProviderReleaseDataCallback) | 58 | let dataProvider = CGDataProvider(dataInfo: nil, data: bytesPointer, size: data?.count ?? 0, releaseData: dataProviderReleaseDataCallback) |
| 58 | pdfDocument = CGPDFDocument(dataProvider!) | 59 | pdfDocument = CGPDFDocument(dataProvider!) |
| 59 | 60 | ||
| 60 | - let controller = UIPrintInteractionController.shared | ||
| 61 | - controller.delegate = self | ||
| 62 | - | ||
| 63 | - let printInfo = UIPrintInfo.printInfo() | ||
| 64 | - printInfo.jobName = jobName! | ||
| 65 | - printInfo.outputType = .general | ||
| 66 | - if orientation != nil { | ||
| 67 | - printInfo.orientation = orientation! | ||
| 68 | - orientation = nil | ||
| 69 | - } | ||
| 70 | - controller.printInfo = printInfo | ||
| 71 | - controller.printPageRenderer = self | ||
| 72 | - controller.present(animated: true, completionHandler: completionHandler) | 61 | + // Unblock the main thread |
| 62 | + semaphore.signal() | ||
| 73 | } | 63 | } |
| 74 | 64 | ||
| 75 | override public var numberOfPages: Int { | 65 | override public var numberOfPages: Int { |
| 76 | - let pages = pdfDocument?.numberOfPages ?? 0 | ||
| 77 | - return pages | 66 | + printing.onLayout( |
| 67 | + printJob: self, | ||
| 68 | + width: paperRect.size.width, | ||
| 69 | + height: paperRect.size.height, | ||
| 70 | + marginLeft: printableRect.origin.x, | ||
| 71 | + marginTop: printableRect.origin.y, | ||
| 72 | + marginRight: paperRect.size.width - (printableRect.origin.x + printableRect.size.width), | ||
| 73 | + marginBottom: paperRect.size.height - (printableRect.origin.y + printableRect.size.height) | ||
| 74 | + ) | ||
| 75 | + | ||
| 76 | + // Block the main thread, waiting for a document | ||
| 77 | + semaphore.wait() | ||
| 78 | + | ||
| 79 | + return pdfDocument?.numberOfPages ?? 0 | ||
| 78 | } | 80 | } |
| 79 | 81 | ||
| 80 | func completionHandler(printController _: UIPrintInteractionController, completed: Bool, error: Error?) { | 82 | func completionHandler(printController _: UIPrintInteractionController, completed: Bool, error: Error?) { |
| @@ -110,7 +112,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | @@ -110,7 +112,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | ||
| 110 | controller.print(to: printer, completionHandler: completionHandler) | 112 | controller.print(to: printer, completionHandler: completionHandler) |
| 111 | } | 113 | } |
| 112 | 114 | ||
| 113 | - func printPdf(name: String, withPageSize size: CGSize, andMargin margin: CGRect) { | 115 | + func printPdf(name: String, withPageSize size: CGSize, andMargin _: CGRect) { |
| 114 | let printing = UIPrintInteractionController.isPrintingAvailable | 116 | let printing = UIPrintInteractionController.isPrintingAvailable |
| 115 | if !printing { | 117 | if !printing { |
| 116 | self.printing.onCompleted(printJob: self, completed: false, error: "Printing not available") | 118 | self.printing.onCompleted(printJob: self, completed: false, error: "Printing not available") |
| @@ -123,15 +125,21 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | @@ -123,15 +125,21 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | ||
| 123 | 125 | ||
| 124 | jobName = name | 126 | jobName = name |
| 125 | 127 | ||
| 126 | - self.printing.onLayout( | ||
| 127 | - printJob: self, | ||
| 128 | - width: size.width, | ||
| 129 | - height: size.height, | ||
| 130 | - marginLeft: margin.minX, | ||
| 131 | - marginTop: margin.minY, | ||
| 132 | - marginRight: size.width - margin.maxX, | ||
| 133 | - marginBottom: size.height - margin.maxY | ||
| 134 | - ) | 128 | + let controller = UIPrintInteractionController.shared |
| 129 | + controller.delegate = self | ||
| 130 | + | ||
| 131 | + let printInfo = UIPrintInfo.printInfo() | ||
| 132 | + printInfo.jobName = jobName! | ||
| 133 | + printInfo.outputType = .general | ||
| 134 | + if orientation != nil { | ||
| 135 | + printInfo.orientation = orientation! | ||
| 136 | + orientation = nil | ||
| 137 | + } | ||
| 138 | + controller.printInfo = printInfo | ||
| 139 | + controller.showsPaperSelectionForLoadedPapers = true | ||
| 140 | + | ||
| 141 | + controller.printPageRenderer = self | ||
| 142 | + controller.present(animated: true, completionHandler: completionHandler) | ||
| 135 | } | 143 | } |
| 136 | 144 | ||
| 137 | static func sharePdf(data: Data, withSourceRect rect: CGRect, andName name: String) { | 145 | static func sharePdf(data: Data, withSourceRect rect: CGRect, andName name: String) { |
| @@ -287,7 +295,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | @@ -287,7 +295,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | ||
| 287 | public static func printingInfo() -> NSDictionary { | 295 | public static func printingInfo() -> NSDictionary { |
| 288 | let data: NSDictionary = [ | 296 | let data: NSDictionary = [ |
| 289 | "directPrint": true, | 297 | "directPrint": true, |
| 290 | - "dynamicLayout": false, | 298 | + "dynamicLayout": true, |
| 291 | "canPrint": true, | 299 | "canPrint": true, |
| 292 | "canConvertHtml": true, | 300 | "canConvertHtml": true, |
| 293 | "canShare": true, | 301 | "canShare": true, |
| @@ -17,12 +17,29 @@ | @@ -17,12 +17,29 @@ | ||
| 17 | import Flutter | 17 | import Flutter |
| 18 | import Foundation | 18 | import Foundation |
| 19 | 19 | ||
| 20 | +// Dart:ffi API | ||
| 21 | +private var _printingPlugin: PrintingPlugin? | ||
| 22 | + | ||
| 23 | +@_cdecl("net_nfet_printing_set_document") | ||
| 24 | +func setDocument(job: UInt32, doc: UnsafePointer<UInt8>, size: UInt64) { | ||
| 25 | + _printingPlugin!.jobs[job]?.setDocument(Data(bytes: doc, count: Int(size))) | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +@_cdecl("net_nfet_printing_set_error") | ||
| 29 | +func setError(job: UInt32, message: UnsafePointer<CChar>) { | ||
| 30 | + _printingPlugin!.jobs[job]?.cancelJob(String(cString: message)) | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +// End of Dart:ffi API | ||
| 34 | + | ||
| 20 | public class PrintingPlugin: NSObject, FlutterPlugin { | 35 | public class PrintingPlugin: NSObject, FlutterPlugin { |
| 21 | private var channel: FlutterMethodChannel | 36 | private var channel: FlutterMethodChannel |
| 37 | + public var jobs = [UInt32: PrintJob]() | ||
| 22 | 38 | ||
| 23 | init(_ channel: FlutterMethodChannel) { | 39 | init(_ channel: FlutterMethodChannel) { |
| 24 | self.channel = channel | 40 | self.channel = channel |
| 25 | super.init() | 41 | super.init() |
| 42 | + _printingPlugin = self | ||
| 26 | } | 43 | } |
| 27 | 44 | ||
| 28 | /// Entry point | 45 | /// Entry point |
| @@ -44,6 +61,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | @@ -44,6 +61,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | ||
| 44 | let marginRight = CGFloat((args["marginRight"] as? NSNumber)?.floatValue ?? 0.0) | 61 | let marginRight = CGFloat((args["marginRight"] as? NSNumber)?.floatValue ?? 0.0) |
| 45 | let marginBottom = CGFloat((args["marginBottom"] as? NSNumber)?.floatValue ?? 0.0) | 62 | let marginBottom = CGFloat((args["marginBottom"] as? NSNumber)?.floatValue ?? 0.0) |
| 46 | let printJob = PrintJob(printing: self, index: args["job"] as! Int) | 63 | let printJob = PrintJob(printing: self, index: args["job"] as! Int) |
| 64 | + jobs[args["job"] as! UInt32] = printJob | ||
| 47 | printJob.printPdf(name: name, | 65 | printJob.printPdf(name: name, |
| 48 | withPageSize: CGSize( | 66 | withPageSize: CGSize( |
| 49 | width: width, | 67 | width: width, |
| @@ -137,19 +155,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | @@ -137,19 +155,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | ||
| 137 | "job": printJob.index, | 155 | "job": printJob.index, |
| 138 | ] as [String: Any] | 156 | ] as [String: Any] |
| 139 | 157 | ||
| 140 | - channel.invokeMethod("onLayout", arguments: arg, result: { (result: Any?) -> Void in | ||
| 141 | - if result as? Bool == false { | ||
| 142 | - printJob.cancelJob(nil) | ||
| 143 | - } else if result is FlutterError { | ||
| 144 | - let error = result as! FlutterError | ||
| 145 | - printJob.cancelJob(error.message) | ||
| 146 | - } else if result is FlutterStandardTypedData { | ||
| 147 | - let object = result as! FlutterStandardTypedData | ||
| 148 | - printJob.setDocument(object.data) | ||
| 149 | - } else { | ||
| 150 | - printJob.cancelJob("Unknown data type") | ||
| 151 | - } | ||
| 152 | - }) | 158 | + channel.invokeMethod("onLayout", arguments: arg) |
| 153 | } | 159 | } |
| 154 | 160 | ||
| 155 | /// send completion status to flutter | 161 | /// send completion status to flutter |
| @@ -160,6 +166,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | @@ -160,6 +166,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | ||
| 160 | "job": printJob.index, | 166 | "job": printJob.index, |
| 161 | ] | 167 | ] |
| 162 | channel.invokeMethod("onCompleted", arguments: data) | 168 | channel.invokeMethod("onCompleted", arguments: data) |
| 169 | + jobs.removeValue(forKey: UInt32(printJob.index)) | ||
| 163 | } | 170 | } |
| 164 | 171 | ||
| 165 | /// send html to pdf data result to flutter | 172 | /// send html to pdf data result to flutter |
| @@ -15,11 +15,13 @@ | @@ -15,11 +15,13 @@ | ||
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | import 'dart:async'; | 17 | import 'dart:async'; |
| 18 | +import 'dart:io'; | ||
| 18 | import 'dart:typed_data'; | 19 | import 'dart:typed_data'; |
| 19 | 20 | ||
| 20 | import 'package:flutter/rendering.dart' show Rect; | 21 | import 'package:flutter/rendering.dart' show Rect; |
| 21 | import 'package:flutter/services.dart'; | 22 | import 'package:flutter/services.dart'; |
| 22 | import 'package:pdf/pdf.dart'; | 23 | import 'package:pdf/pdf.dart'; |
| 24 | +import 'package:printing/src/method_channel_ffi.dart'; | ||
| 23 | 25 | ||
| 24 | import 'callback.dart'; | 26 | import 'callback.dart'; |
| 25 | import 'interface.dart'; | 27 | import 'interface.dart'; |
| @@ -56,7 +58,20 @@ class MethodChannelPrinting extends PrintingPlatform { | @@ -56,7 +58,20 @@ class MethodChannelPrinting extends PrintingPlatform { | ||
| 56 | marginBottom: call.arguments['marginBottom'], | 58 | marginBottom: call.arguments['marginBottom'], |
| 57 | ); | 59 | ); |
| 58 | 60 | ||
| 59 | - final bytes = await job.onLayout!(format); | 61 | + Uint8List bytes; |
| 62 | + try { | ||
| 63 | + bytes = await job.onLayout!(format); | ||
| 64 | + } catch (e) { | ||
| 65 | + if (Platform.isMacOS || Platform.isIOS) { | ||
| 66 | + return setErrorFfi(job, e.toString()); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + rethrow; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + if (Platform.isMacOS || Platform.isIOS) { | ||
| 73 | + return setDocumentFfi(job, bytes); | ||
| 74 | + } | ||
| 60 | 75 | ||
| 61 | return Uint8List.fromList(bytes); | 76 | return Uint8List.fromList(bytes); |
| 62 | case 'onCompleted': | 77 | case 'onCompleted': |
printing/lib/src/method_channel_ffi.dart
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +import 'dart:ffi' as ffi; | ||
| 18 | +import 'dart:io' as io; | ||
| 19 | +import 'dart:typed_data'; | ||
| 20 | + | ||
| 21 | +import 'package:ffi/ffi.dart' as ffi; | ||
| 22 | + | ||
| 23 | +import 'print_job.dart'; | ||
| 24 | + | ||
| 25 | +/// Load the dynamic library | ||
| 26 | +final ffi.DynamicLibrary _dynamicLibrary = _open(); | ||
| 27 | +ffi.DynamicLibrary _open() { | ||
| 28 | + if (io.Platform.isMacOS || io.Platform.isIOS) { | ||
| 29 | + return ffi.DynamicLibrary.process(); | ||
| 30 | + } | ||
| 31 | + throw UnsupportedError('This platform is not supported.'); | ||
| 32 | +} | ||
| 33 | + | ||
| 34 | +/// Set the Pdf document data | ||
| 35 | +void setDocumentFfi(PrintJob job, Uint8List data) { | ||
| 36 | + final nativeBytes = ffi.allocate<ffi.Uint8>(count: data.length); | ||
| 37 | + nativeBytes.asTypedList(data.length).setAll(0, data); | ||
| 38 | + _setDocument(job.index, nativeBytes, data.length); | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +final _SetDocument_Dart _setDocument = | ||
| 42 | + _dynamicLibrary.lookupFunction<_SetDocument_C, _SetDocument_Dart>( | ||
| 43 | + 'net_nfet_printing_set_document', | ||
| 44 | +); | ||
| 45 | + | ||
| 46 | +typedef _SetDocument_C = ffi.Void Function( | ||
| 47 | + ffi.Uint32 job, | ||
| 48 | + ffi.Pointer<ffi.Uint8> data, | ||
| 49 | + ffi.Uint64 size, | ||
| 50 | +); | ||
| 51 | + | ||
| 52 | +typedef _SetDocument_Dart = void Function( | ||
| 53 | + int job, | ||
| 54 | + ffi.Pointer<ffi.Uint8> data, | ||
| 55 | + int size, | ||
| 56 | +); | ||
| 57 | + | ||
| 58 | +/// Set the Pdf Error message | ||
| 59 | +void setErrorFfi(PrintJob job, String message) { | ||
| 60 | + _setError(job.index, ffi.Utf8.toUtf8(message)); | ||
| 61 | +} | ||
| 62 | + | ||
| 63 | +final _SetError_Dart _setError = | ||
| 64 | + _dynamicLibrary.lookupFunction<_SetError_C, _SetError_Dart>( | ||
| 65 | + 'net_nfet_printing_set_error', | ||
| 66 | +); | ||
| 67 | + | ||
| 68 | +typedef _SetError_C = ffi.Void Function( | ||
| 69 | + ffi.Uint32 job, | ||
| 70 | + ffi.Pointer<ffi.Utf8> message, | ||
| 71 | +); | ||
| 72 | + | ||
| 73 | +typedef _SetError_Dart = void Function( | ||
| 74 | + int job, | ||
| 75 | + ffi.Pointer<ffi.Utf8> message, | ||
| 76 | +); |
| @@ -29,6 +29,7 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { | @@ -29,6 +29,7 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { | ||
| 29 | private var printOperation: NSPrintOperation? | 29 | private var printOperation: NSPrintOperation? |
| 30 | private var pdfDocument: CGPDFDocument? | 30 | private var pdfDocument: CGPDFDocument? |
| 31 | private var page: CGPDFPage? | 31 | private var page: CGPDFPage? |
| 32 | + private let semaphore = DispatchSemaphore(value: 0) | ||
| 32 | 33 | ||
| 33 | public init(printing: PrintingPlugin, index: Int) { | 34 | public init(printing: PrintingPlugin, index: Int) { |
| 34 | self.printing = printing | 35 | self.printing = printing |
| @@ -47,7 +48,29 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { | @@ -47,7 +48,29 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { | ||
| 47 | 48 | ||
| 48 | setFrameSize(size) | 49 | setFrameSize(size) |
| 49 | setBoundsSize(size) | 50 | setBoundsSize(size) |
| 50 | - range.pointee.length = pdfDocument?.numberOfPages ?? 0 | 51 | + |
| 52 | + printing.onLayout( | ||
| 53 | + printJob: self, | ||
| 54 | + width: printOperation!.printInfo.paperSize.width, | ||
| 55 | + height: printOperation!.printInfo.paperSize.height, | ||
| 56 | + marginLeft: printOperation!.printInfo.leftMargin, | ||
| 57 | + marginTop: printOperation!.printInfo.topMargin, | ||
| 58 | + marginRight: printOperation!.printInfo.rightMargin, | ||
| 59 | + marginBottom: printOperation!.printInfo.bottomMargin | ||
| 60 | + ) | ||
| 61 | + | ||
| 62 | + // Block the main thread, waiting for a document | ||
| 63 | + semaphore.wait() | ||
| 64 | + | ||
| 65 | + if pdfDocument != nil { | ||
| 66 | + range.pointee.length = pdfDocument!.numberOfPages | ||
| 67 | + let page = pdfDocument!.page(at: 1) | ||
| 68 | + let size = page?.getBoxRect(CGPDFBox.mediaBox) ?? NSZeroRect | ||
| 69 | + setFrameSize(size.size) | ||
| 70 | + setBoundsSize(size.size) | ||
| 71 | + } else { | ||
| 72 | + range.pointee.length = 0 | ||
| 73 | + } | ||
| 51 | return true | 74 | return true |
| 52 | } | 75 | } |
| 53 | 76 | ||
| @@ -67,8 +90,8 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { | @@ -67,8 +90,8 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { | ||
| 67 | let dataProvider = CGDataProvider(dataInfo: nil, data: bytesPointer, size: data?.count ?? 0, releaseData: dataProviderReleaseDataCallback) | 90 | let dataProvider = CGDataProvider(dataInfo: nil, data: bytesPointer, size: data?.count ?? 0, releaseData: dataProviderReleaseDataCallback) |
| 68 | pdfDocument = CGPDFDocument(dataProvider!) | 91 | pdfDocument = CGPDFDocument(dataProvider!) |
| 69 | 92 | ||
| 70 | - let window = NSApplication.shared.mainWindow! | ||
| 71 | - printOperation!.runModal(for: window, delegate: self, didRun: #selector(printOperationDidRun(printOperation:success:contextInfo:)), contextInfo: nil) | 93 | + // Unblock the main thread |
| 94 | + semaphore.signal() | ||
| 72 | } | 95 | } |
| 73 | 96 | ||
| 74 | override public func draw(_: NSRect) { | 97 | override public func draw(_: NSRect) { |
| @@ -136,21 +159,15 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { | @@ -136,21 +159,15 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { | ||
| 136 | // Print the custom view | 159 | // Print the custom view |
| 137 | printOperation = NSPrintOperation(view: self, printInfo: printInfo) | 160 | printOperation = NSPrintOperation(view: self, printInfo: printInfo) |
| 138 | printOperation!.jobTitle = name | 161 | printOperation!.jobTitle = name |
| 139 | - printOperation!.printPanel.options = [.showsPreview] | 162 | + printOperation!.printPanel.options = [.showsPreview, .showsPaperSize, .showsOrientation] |
| 140 | 163 | ||
| 141 | - printing.onLayout( | ||
| 142 | - printJob: self, | ||
| 143 | - width: printOperation!.printInfo.paperSize.width, | ||
| 144 | - height: printOperation!.printInfo.paperSize.height, | ||
| 145 | - marginLeft: printOperation!.printInfo.leftMargin, | ||
| 146 | - marginTop: printOperation!.printInfo.topMargin, | ||
| 147 | - marginRight: printOperation!.printInfo.rightMargin, | ||
| 148 | - marginBottom: printOperation!.printInfo.bottomMargin | ||
| 149 | - ) | 164 | + let window = NSApplication.shared.mainWindow! |
| 165 | + printOperation!.runModal(for: window, delegate: self, didRun: #selector(printOperationDidRun(printOperation:success:contextInfo:)), contextInfo: nil) | ||
| 150 | } | 166 | } |
| 151 | 167 | ||
| 152 | - func cancelJob(_ error: String?) { | ||
| 153 | - printing.onCompleted(printJob: self, completed: false, error: error as NSString?) | 168 | + func cancelJob(_: String?) { |
| 169 | + pdfDocument = nil | ||
| 170 | + semaphore.signal() | ||
| 154 | } | 171 | } |
| 155 | 172 | ||
| 156 | public static func sharePdf(data: Data, withSourceRect rect: CGRect, andName name: String) { | 173 | public static func sharePdf(data: Data, withSourceRect rect: CGRect, andName name: String) { |
| @@ -17,12 +17,29 @@ | @@ -17,12 +17,29 @@ | ||
| 17 | import FlutterMacOS | 17 | import FlutterMacOS |
| 18 | import Foundation | 18 | import Foundation |
| 19 | 19 | ||
| 20 | +// Dart:ffi API | ||
| 21 | +private var _printingPlugin: PrintingPlugin? | ||
| 22 | + | ||
| 23 | +@_cdecl("net_nfet_printing_set_document") | ||
| 24 | +func setDocument(job: UInt32, doc: UnsafePointer<UInt8>, size: UInt64) { | ||
| 25 | + _printingPlugin!.jobs[job]?.setDocument(Data(bytes: doc, count: Int(size))) | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +@_cdecl("net_nfet_printing_set_error") | ||
| 29 | +func setError(job: UInt32, message: UnsafePointer<CChar>) { | ||
| 30 | + _printingPlugin!.jobs[job]?.cancelJob(String(cString: message)) | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +// End of Dart:ffi API | ||
| 34 | + | ||
| 20 | public class PrintingPlugin: NSObject, FlutterPlugin { | 35 | public class PrintingPlugin: NSObject, FlutterPlugin { |
| 21 | private var channel: FlutterMethodChannel | 36 | private var channel: FlutterMethodChannel |
| 37 | + public var jobs = [UInt32: PrintJob]() | ||
| 22 | 38 | ||
| 23 | init(_ channel: FlutterMethodChannel) { | 39 | init(_ channel: FlutterMethodChannel) { |
| 24 | self.channel = channel | 40 | self.channel = channel |
| 25 | super.init() | 41 | super.init() |
| 42 | + _printingPlugin = self | ||
| 26 | } | 43 | } |
| 27 | 44 | ||
| 28 | /// Entry point | 45 | /// Entry point |
| @@ -44,6 +61,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | @@ -44,6 +61,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | ||
| 44 | let marginRight = CGFloat((args["marginRight"] as? NSNumber)?.floatValue ?? 0.0) | 61 | let marginRight = CGFloat((args["marginRight"] as? NSNumber)?.floatValue ?? 0.0) |
| 45 | let marginBottom = CGFloat((args["marginBottom"] as? NSNumber)?.floatValue ?? 0.0) | 62 | let marginBottom = CGFloat((args["marginBottom"] as? NSNumber)?.floatValue ?? 0.0) |
| 46 | let printJob = PrintJob(printing: self, index: args["job"] as! Int) | 63 | let printJob = PrintJob(printing: self, index: args["job"] as! Int) |
| 64 | + jobs[args["job"] as! UInt32] = printJob | ||
| 47 | printJob.printPdf(name: name, | 65 | printJob.printPdf(name: name, |
| 48 | withPageSize: CGSize( | 66 | withPageSize: CGSize( |
| 49 | width: width, | 67 | width: width, |
| @@ -108,13 +126,6 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | @@ -108,13 +126,6 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | ||
| 108 | andBaseUrl: args["baseUrl"] as? String == nil ? nil : URL(string: args["baseUrl"] as! String) | 126 | andBaseUrl: args["baseUrl"] as? String == nil ? nil : URL(string: args["baseUrl"] as! String) |
| 109 | ) | 127 | ) |
| 110 | result(NSNumber(value: 1)) | 128 | result(NSNumber(value: 1)) |
| 111 | -// } else if call.method == "pickPrinter" { | ||
| 112 | -// PrintJob.pickPrinter(result: result, withSourceRect: CGRect( | ||
| 113 | -// x: CGFloat((args["x"] as? NSNumber)?.floatValue ?? 0.0), | ||
| 114 | -// y: CGFloat((args["y"] as? NSNumber)?.floatValue ?? 0.0), | ||
| 115 | -// width: CGFloat((args["w"] as? NSNumber)?.floatValue ?? 0.0), | ||
| 116 | -// height: CGFloat((args["h"] as? NSNumber)?.floatValue ?? 0.0) | ||
| 117 | -// )) | ||
| 118 | } else if call.method == "printingInfo" { | 129 | } else if call.method == "printingInfo" { |
| 119 | result(PrintJob.printingInfo()) | 130 | result(PrintJob.printingInfo()) |
| 120 | } else if call.method == "rasterPdf" { | 131 | } else if call.method == "rasterPdf" { |
| @@ -143,19 +154,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | @@ -143,19 +154,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | ||
| 143 | "job": printJob.index, | 154 | "job": printJob.index, |
| 144 | ] as [String: Any] | 155 | ] as [String: Any] |
| 145 | 156 | ||
| 146 | - channel.invokeMethod("onLayout", arguments: arg, result: { (result: Any?) -> Void in | ||
| 147 | - if result as? Bool == false { | ||
| 148 | - printJob.cancelJob(nil) | ||
| 149 | - } else if result is FlutterError { | ||
| 150 | - let error = result as! FlutterError | ||
| 151 | - printJob.cancelJob(error.message) | ||
| 152 | - } else if result is FlutterStandardTypedData { | ||
| 153 | - let object = result as! FlutterStandardTypedData | ||
| 154 | - printJob.setDocument(object.data) | ||
| 155 | - } else { | ||
| 156 | - printJob.cancelJob("Unknown data type") | ||
| 157 | - } | ||
| 158 | - }) | 157 | + channel.invokeMethod("onLayout", arguments: arg) |
| 159 | } | 158 | } |
| 160 | 159 | ||
| 161 | /// send completion status to flutter | 160 | /// send completion status to flutter |
| @@ -166,6 +165,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | @@ -166,6 +165,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | ||
| 166 | "job": printJob.index, | 165 | "job": printJob.index, |
| 167 | ] | 166 | ] |
| 168 | channel.invokeMethod("onCompleted", arguments: data) | 167 | channel.invokeMethod("onCompleted", arguments: data) |
| 168 | + jobs.removeValue(forKey: UInt32(printJob.index)) | ||
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | /// send html to pdf data result to flutter | 171 | /// send html to pdf data result to flutter |
-
Please register or login to post a comment