• Stars
    star
    107
  • Rank 323,587 (Top 7 %)
  • Language
    Objective-C
  • License
    MIT License
  • Created about 5 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Unlock missing UIKit functionality with these AppKit helpers

Catalyst-Helpers

Unlock missing UIKit functionality with these unsafe AppKit helpers. The overall goal is to let Apple know what functionality is missing in UIKit to build better apps for the Mac.

IPDFMacEventBus & Keyboard Navigation

The fundamental aspect of what sets iOS (excluding tvOS) aparat form macOS is the inability to correctly navigate through views, not only text fields, with a keyboard. I've come to realise that a UIKeyCommand is not enough and sometimes you would simply be better off with keyDown:, which iOS lacks. So I've wrapped NSEvent's addLocalMonitorForEventsMatchingMask - where you are able to choose whether an event actually gets passed to UIKit or not. Always remember to removeMonitor: otherwhise you'll be left with leaks everywhere.

IPDFMacEventBusMonitor *monitor = [IPDFMacEventBusMonitor monitorWithType:IPDFMacEventBusTypeKeydown eventHandler:^IPDFMacEventBusEvent *(IPDFMacEventBusEvent *event)
{
    if ([event isTab])
    {
        if (weakSelf.cancel.isFirstResponder)
        {
            [weakSelf.save becomeFirstResponder];
            return nil;
        }

        if (weakSelf.save.isFirstResponder)
        {
            [weakSelf.textField becomeFirstResponder];
            return nil;
        }

        if (weakSelf.textField.isFirstResponder)
        {
            [weakSelf.cancel becomeFirstResponder];
            return nil;
        }
    }

    if ([event isEnter])
    {
        if (weakSelf.cancel.isFirstResponder)
        {
            [weakSelf.cancel sendActionsForControlEvents:UIControlEventTouchUpInside];
            return nil;
        }

        if (weakSelf.save.isFirstResponder)
        {
            [weakSelf.save sendActionsForControlEvents:UIControlEventTouchUpInside];
            return nil;
        }
    }

    if ([event isESC])
    {
        [weakSelf dismissWithCompletionHandler:nil];
        return nil;
    }

    return event;
}];
sheet.monitor = monitor;
[[IPDFMacEventBus sharedBus] addMonitor:monitor];

IPDFMacEventBus & App State Events

InstaPDF doesn't fetch documents in the background, but rather when the window becomes key. At first it was quite confusing not being able to know when this occurs, due to UIApplicationWillEnterForegroundNotification only firing once on launch. I pondered swizzling, but observing notifications is a better solution. Again, remove the monitors to prevent leaks.

[[IPDFMacEventBus sharedBus] addMonitor:[IPDFMacEventBusMonitor monitorWithType:IPDFMacEventBusTypeAppState eventHandler:^IPDFMacEventBusEvent *(IPDFMacEventBusEvent *event)
{
    if (event.appState == IPDFMacEventBusAppStateEventBecomeActive)
    {
        NSLog(@"Become Active");
    }

    if (event.appState == IPDFMacEventBusAppStateEventTerminate)
    {
        NSLog(@"Terminate...");
    }
    return nil;
}]];

Additional Catalyst Workarounds

In addition to the helper classes I created, there were still some visual glitches and other unexpected behaviour in UIKit that will feel foreign on the Mac that cannot be abstracted

Opening Files from Dock Icon & Right-Click Finder "Open In..."

You'll need to swizzle (I prefer https://github.com/steipete/Aspects).

  1. Add appropriate entry to Info.plist, .pdf files in the example below
<array>
	<dict>
		<key>CFBundleTypeExtensions</key>
		<array>
			<string>pdf</string>
		</array>
		<key>CFBundleTypeIconFiles</key>
		<array/>
		<key>CFBundleTypeName</key>
		<string>PDF Document</string>
		<key>CFBundleTypeRole</key>
		<string>Editor</string>
		<key>LSHandlerRank</key>
		<string>Owner</string>
		<key>LSItemContentTypes</key>
		<array>
			<string>com.adobe.pdf</string>
		</array>
	</dict>
</array>
  1. Declare the appropriate selector to hook in AppDelegate
@interface AppDelegate ()

@end

@interface NSObject (private)

- (void)processOpenURLs:(id)arg1;

@end
  1. Hook the selector and process the files
__weak typeof(self) weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:@"NSApplicationDidFinishLaunchingNotification" object:nil queue:nil usingBlock:^(NSNotification *note)
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        id app = [NSClassFromString(@"NSApplication") sharedApplication];
        id delegate = [app delegate];

        [delegate aspect_hookSelector:@selector(processOpenURLs:) withOptions:AspectPositionInstead usingBlock:^(id<AspectInfo> aspectInfo, NSArray *fileURLs)
        {
            [weakSelf openFiles:fileURLs];
        } error:nil];
    });
}];

Before the dock would allow me to drag in files, I had to either: run a different project in Xcode after the plist entry or restart the OS. I can't remember which one helped.

Blue highlights in UITableViewCell on selection

Double clicking causes the cell to highlight blue

When embedding a UITableView on the left panel of a UISplitView (self.primaryBackgroundStyle = UISplitViewControllerBackgroundStyleSidebar), the design will mimick NSOutlineView. This design is found in apps such as Xcode, Mail, Finder, etc. The difference between Xcode and Finder for example, is that Finder will not allow the cell to be highlighted, because it cannot become a firstResponder.

NSOutlineView in Finder design

On the Catalyst side of things, a click and subsequent selection of a given cell can cause the blue (or the user's chosen accent color) highlight to shimmer/glitch through. On a double click, the cell will turn blue. There is no apparent way to prevent the cell from changing to a solid color on double click without having to implement your own custom selectedBackgroundView and therefore losing the UIVibrancyEffect on selection.

The workaround is quite simple (took me a while): add a UITapGestureRecognizer (numberOfTapsRequired = 1) to your cell. You'll have to manually create a protocol and then select the cell. Once these measures are implemented, double clicking will no longer turn the cell blue and the behaviour will be indistinguishable from a native app like Finder.

More Repositories

1

Hacker-News-for-iOS

Hacker News client for iPad and iPhone [DEPRECATED]
Objective-C
588
star
2

MAImagePickerController-of-InstaPDF

Fully customizable UIImagePicker replacement with flexible cropping, filters, perspective correction, rotation etc.
C++
516
star
3

KEYPullDownMenu

A pull down menu, similar to notification center on iOS that supports an unlimited number of items. Items can either be selected, deleted or reordered. The control is aimed at providing context for switching data within the same view controller.
Objective-C
262
star
4

BaseComponents

BaseComponents aims to provide easily reusable and understandable components to increase productivity with UIKit and Foundation APIs
Swift
141
star
5

PCRapidSelectionView

Interactive, beautiful & fast UIActionSheet replacement, supports continuous hold & select
Objective-C
67
star
6

Clear-Read-API

Extracts article text and metadata from a given URL
PHP
35
star
7

PCSplitView

Super powerful layout for iOS, simplified.
Objective-C
24
star
8

Editor

Custom UIKit Text Editor Component for Catalyst
Swift
16
star
9

Next-Airport

Open source RFML (RedFoundry.com) iPhone app
14
star
10

MStaff

3rd Party WhenIWork.com iOS Client app with multiple account support built for Hotel Marietta, Obertauern
Objective-C
6
star
11

Broadcast.io

Demo Node.js + iOS app that is entirly based on MessagesTableViewController & socket.IO-objc
Objective-C
6
star
12

wrrrite

Start writing, effortlessly & distraction free.
PHP
5
star
13

p-body

Static Blog + PHP + Markdown + CSS Formatting
PHP
4
star
14

Preview

Open Source replacement for RedFoundry Visualizer written in RFML
3
star
15

MMFatPipe

Image Resize + Asynchronous Upload
Objective-C
3
star
16

The-Queue

A ultra light-weight (& basic) Blogging engine: 57kb
PHP
2
star
17

InterfaceBuilder.swift-Demo

Swift
2
star
18

RFMLight

A proposition for a new RFML Format
JavaScript
1
star