Skip to content

Commit

Permalink
Add support for printing inline PDF's
Browse files Browse the repository at this point in the history
Related to #40
  • Loading branch information
joelekstrom committed Jun 25, 2021
1 parent 39b1d03 commit 928a20a
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 14 deletions.
16 changes: 14 additions & 2 deletions Fastmate.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
5D0F8E95240B910A00287BD1 /* PrintManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D0F8E94240B910A00287BD1 /* PrintManager.m */; };
5D14A8EB22C425B400A5ACE9 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 5D14A8EA22C425B400A5ACE9 /* Credits.rtf */; };
5D18D5022685E2EC002999F0 /* PDFKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D18D5012685E2EC002999F0 /* PDFKit.framework */; };
5D39BEDB2122383800693D7E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D39BEDA2122383800693D7E /* AppDelegate.m */; };
5D39BEDD2122383900693D7E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5D39BEDC2122383900693D7E /* Assets.xcassets */; };
5D39BEE32122383900693D7E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D39BEE22122383900693D7E /* main.m */; };
Expand All @@ -27,6 +28,7 @@
5D0F8E93240B910A00287BD1 /* PrintManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PrintManager.h; sourceTree = "<group>"; };
5D0F8E94240B910A00287BD1 /* PrintManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PrintManager.m; sourceTree = "<group>"; };
5D14A8EA22C425B400A5ACE9 /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
5D18D5012685E2EC002999F0 /* PDFKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PDFKit.framework; path = System/Library/Frameworks/PDFKit.framework; sourceTree = SDKROOT; };
5D39BED62122383800693D7E /* Fastmate.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Fastmate.app; sourceTree = BUILT_PRODUCTS_DIR; };
5D39BED92122383800693D7E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
5D39BEDA2122383800693D7E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -58,17 +60,27 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5D18D5022685E2EC002999F0 /* PDFKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
5D18D5002685E2EC002999F0 /* Frameworks */ = {
isa = PBXGroup;
children = (
5D18D5012685E2EC002999F0 /* PDFKit.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
5D39BECD2122383700693D7E = {
isa = PBXGroup;
children = (
5D39BED82122383800693D7E /* Fastmate */,
5D39BED72122383800693D7E /* Products */,
5D18D5002685E2EC002999F0 /* Frameworks */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -341,7 +353,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 1.6.5;
MARKETING_VERSION = 1.6.6;
PRODUCT_BUNDLE_IDENTIFIER = io.ekstrom.Fastmate;
PRODUCT_NAME = "$(TARGET_NAME)";
};
Expand All @@ -364,7 +376,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 1.6.5;
MARKETING_VERSION = 1.6.6;
PRODUCT_BUNDLE_IDENTIFIER = io.ekstrom.Fastmate;
PRODUCT_NAME = "$(TARGET_NAME)";
};
Expand Down
2 changes: 1 addition & 1 deletion Fastmate/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ - (IBAction)performFindPanelAction:(id)sender {
}

- (IBAction)print:(id)sender {
[[PrintManager sharedInstance] printWebView:self.mainWebViewController.webView];
[[PrintManager sharedInstance] printControllerContent:self.mainWebViewController];
}

- (void)setStatusItemVisible:(BOOL)visible {
Expand Down
3 changes: 2 additions & 1 deletion Fastmate/PrintManager.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#import <Foundation/Foundation.h>
#import "WebViewController.h"

@class WKWebView;

Expand All @@ -12,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface PrintManager : NSObject

+ (instancetype)sharedInstance;
- (void)printWebView:(WKWebView *)webView;
- (void)printControllerContent:(WebViewController *)controller;

@end

Expand Down
40 changes: 31 additions & 9 deletions Fastmate/PrintManager.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#import "PrintManager.h"
@import WebKit;
@import PDFKit;

@interface PrintManager() <WebFrameLoadDelegate, WebUIDelegate>

Expand Down Expand Up @@ -35,7 +36,9 @@ - (instancetype)init {
return self;
}

- (void)printWebView:(WKWebView *)sourceView {
- (void)printControllerContent:(WebViewController *)controller {
WKWebView *sourceView = controller.webView;

NSRect webViewFrame = NSMakeRect(0, 0, self.printInfo.paperSize.width, self.printInfo.paperSize.height);
self.webView = [[WebView alloc] initWithFrame:webViewFrame frameName:@"printFrame" groupName:@"printGroup"];
self.webView.shouldUpdateWhileOffscreen = true;
Expand All @@ -51,10 +54,24 @@ - (void)printWebView:(WKWebView *)sourceView {
self.emailTitle = [sourceView.title substringWithRange:[result rangeAtIndex:1]];
}

[sourceView evaluateJavaScript:@"document.documentElement.outerHTML.toString()"
completionHandler:^(NSString *HTML, NSError *error) {
[self.webView.mainFrame loadHTMLString:HTML baseURL:NSBundle.mainBundle.resourceURL];
}];
if (controller.currentlyViewedAttachment && [controller.currentlyViewedAttachment.absoluteString containsString:@".pdf"]) {
// If user is viewing a PDF attachment, we can print that directly
[self printPDF:controller.currentlyViewedAttachment];
} else {
// Otherwise, take the HTML body and put it in the new web view
[sourceView evaluateJavaScript:@"document.documentElement.outerHTML.toString()"
completionHandler:^(NSString *HTML, NSError *error) {
[self.webView.mainFrame loadHTMLString:HTML baseURL:NSBundle.mainBundle.resourceURL];
}];
}

}

- (void)printPDF:(NSURL *)pdfURL
{
PDFDocument *document = [[PDFDocument alloc] initWithURL:pdfURL];
NSPrintOperation *printOperation = [document printOperationForPrintInfo:_printInfo scalingMode:kPDFPrintPageScaleToFit autoRotate:YES];
[self runPrintOperation:printOperation];
}

- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
Expand All @@ -66,15 +83,20 @@ - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if ([[sender stringByEvaluatingJavaScriptFromString:@"document.readyState"] isEqualToString:@"complete"]) {
sender.frameLoadDelegate = nil;
NSWindow *window = NSApp.mainWindow ?: NSApp.windows.firstObject;
NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:frame.frameView.documentView printInfo:self.printInfo];
printOperation.jobTitle = self.emailTitle;
self.currentOperation = printOperation;
[printOperation runOperationModalForWindow:window delegate:self didRunSelector:@selector(printOperationDidFinish) contextInfo:nil];
[self runPrintOperation:printOperation];
}
});
}

- (void)runPrintOperation:(NSPrintOperation *)printOperation
{
printOperation.jobTitle = self.emailTitle;
self.currentOperation = printOperation;
NSWindow *window = NSApp.mainWindow ?: NSApp.windows.firstObject;
[printOperation runOperationModalForWindow:window delegate:self didRunSelector:@selector(printOperationDidFinish) contextInfo:nil];
}

- (void)printOperationDidFinish {
self.webView = nil;
}
Expand Down
1 change: 1 addition & 0 deletions Fastmate/WebViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
- (void)reload;

@property (nonatomic, strong) NSDictionary<NSString *, NSNumber *> *mailboxes; // Name -> unreadCount
@property (nonatomic, strong) NSURL *currentlyViewedAttachment;

@end
16 changes: 15 additions & 1 deletion Fastmate/WebViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ @interface WebViewController () <WKNavigationDelegate, WKUIDelegate, WKScriptMes
@property (nonatomic, strong) NSURL *baseURL;
@property (nonatomic, strong) NSTextField *linkPreviewTextField;

// If the user is for example viewing a PDF inline, this value will point to the actual file
@property (nonatomic, strong) NSURL *lastViewedUserContent;

@end

@implementation WebViewController
Expand Down Expand Up @@ -47,12 +50,22 @@ - (void)viewDidLoad {
}];
}

- (NSURL *)currentlyViewedAttachment
{
NSString *attachmentID = [[self.webView.URL.lastPathComponent componentsSeparatedByString:@"."] lastObject];
if ([self.lastViewedUserContent.absoluteString containsString:attachmentID]) {
return self.lastViewedUserContent;
}
return nil;
}

- (void)reload {
[self.webView reload];
}

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
BOOL isFastmailLink = [navigationAction.request.URL.host hasSuffix:@".fastmail.com"];
self.lastViewedUserContent = nil;

if (webView == self.temporaryWebView) {
// A temporary web view means we caught a link URL which Fastmail wants to open externally (like a new tab).
Expand All @@ -70,6 +83,7 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati
[NSWorkspace.sharedWorkspace openURL:navigationAction.request.URL];
decisionHandler(WKNavigationActionPolicyCancel);
} else {
self.lastViewedUserContent = navigationAction.request.URL;
decisionHandler(WKNavigationActionPolicyAllow);
}
} else if (isFastmailLink) {
Expand Down Expand Up @@ -200,7 +214,7 @@ - (void)userContentController:(WKUserContentController *)userContentController d
[self queryToolbarColor];
[self updateUnreadCounts];
} else if ([message.body isEqualToString:@"print"]) {
[PrintManager.sharedInstance printWebView:self.webView];
[PrintManager.sharedInstance printControllerContent:self];
} else {
[self postNotificationForMessage:message];
}
Expand Down

0 comments on commit 928a20a

Please sign in to comment.