Skip to content

Instantly share code, notes, and snippets.

@NSExceptional
Last active August 16, 2017 05:03
Show Gist options
  • Save NSExceptional/ef907df6089d5ee2aee58a034318e127 to your computer and use it in GitHub Desktop.
Save NSExceptional/ef907df6089d5ee2aee58a034318e127 to your computer and use it in GitHub Desktop.
A tweak to enable long-press to copy the text/source/link of a comment in Reddit.app
//
// CommentsViewController+LongPress.m
// RedditEasyCopy
//
// Created by Tanner Bennett on 2017-08-11
//
// This is the "non-tweak" version of the relevant code.
// The .xm file is a tweak, you can ignore it. This file
// has the code that should be put into the app itself.
//
@interface TBMenuItem : UIMenuItem
+ (instancetype)title:(NSString *)title action:(SEL)action copy:(NSString *)string;
@property (nonatomic, readonly) NSString *storage;
@end
@implementation TBMenuItem
+ (instancetype)title:(NSString *)title action:(SEL)action copy:(NSString *)string {
TBMenuItem *item = [[TBMenuItem alloc] initWithTitle:title action:action];
item->_storage = string;
return item;
}
@end
@implementation CommentsViewController
- (void)viewDidLoad {
[super viewDidLoad];
...
UILongPressGestureRecognizer *gesture = [
[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(didLongPressComment:)
];
gesture.minimumPressDuration = .5;
[self.feedCollectionView addGestureRecognizer:gesture];
}
- (void)didLongPressComment:(UILongPressGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateBegan) {
CGPoint point = [gesture locationInView:self.feedCollectionView];
NSIndexPath *ip = [self.feedCollectionView indexPathForItemAtPoint:point];
if (!ip) return;
[self becomeFirstResponder];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:CGRectMake(
point.x - 22, point.y - 22, 44, 44
) inView:self.feedCollectionView];
Comment *comment = self.commentsManager.flattenedObjects[ip.row];
menu.menuItems = @[
[TBMenuItem title:@"Text" action:@selector(copyText:) copy:comment.bodyAttributedText.string],
[TBMenuItem title:@"Source" action:@selector(copySource:) copy:comment.bodyText],
[TBMenuItem title:@"Link" action:@selector(copyLink:) copy:comment.permalink]
];
[menu update];
[menu setMenuVisible:YES animated:YES];
}
}
- (void)copyStorageFromIdx:(NSUInteger)idx of:(UIMenuController *)controller {
TBMenuItem *item = (id)controller.menuItems[idx];
[UIPasteboard generalPasteboard].string = item.storage;
}
// Three separate methods are unfortunately necessary
// because of how convoluted the UIMenuController API is.
- (void)copyText:(UIMenuController *)controller {
[self copyStorageFromIdx:0 of:controller];
}
- (void)copySource:(UIMenuController *)controller {
[self copyStorageFromIdx:1 of:controller];
}
- (void)copyLink:(UIMenuController *)controller {
[self copyStorageFromIdx:2 of:controller];
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
return action == @selector(copyText:) ||
action == @selector(copySource:) ||
action == @selector(copyLink:);
}
- (BOOL)canBecomeFirstResponder { return YES; }
@end
//
// RedditEasyCopy.xm
// RedditEasyCopy
//
// Created by Tanner Bennett on 2017-08-11
// Copyright © 2017 Tanner Bennett. All rights reserved.
//
#import "Interfaces.h"
@interface TBMenuItem : UIMenuItem
+ (instancetype)title:(NSString *)title action:(SEL)action copy:(NSString *)string;
@property (nonatomic, readonly) NSString *storage;
@end
@implementation TBMenuItem
+ (instancetype)title:(NSString *)title action:(SEL)action copy:(NSString *)string {
TBMenuItem *item = [[TBMenuItem alloc] initWithTitle:title action:action];
item->_storage = string;
return item;
}
@end
%hook CommentsViewController
- (void)viewDidLoad {
%orig;
UILongPressGestureRecognizer *gesture = [
[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(didLongPressComment:)
];
gesture.minimumPressDuration = .5;
[self.feedCollectionView addGestureRecognizer:gesture];
}
%new
- (void)didLongPressComment:(UILongPressGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateBegan) {
CGPoint point = [gesture locationInView:self.feedCollectionView];
NSIndexPath *ip = [self.feedCollectionView indexPathForItemAtPoint:point];
if (!ip) return;
[self becomeFirstResponder];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:CGRectMake(
point.x - 22, point.y - 22, 44, 44
) inView:self.feedCollectionView];
Comment *comment = self.commentsManager.flattenedObjects[ip.row];
menu.menuItems = @[
[TBMenuItem title:@"Text" action:@selector(copyText:) copy:comment.bodyAttributedText.string],
[TBMenuItem title:@"Source" action:@selector(copySource:) copy:comment.bodyText],
[TBMenuItem title:@"Link" action:@selector(copyLink:) copy:comment.permalink]
];
[menu update];
[menu setMenuVisible:YES animated:YES];
}
}
%new
- (void)copyStorageFromIdx:(NSUInteger)idx of:(UIMenuController *)controller {
TBMenuItem *item = (id)controller.menuItems[idx];
[UIPasteboard generalPasteboard].string = item.storage;
}
%new
- (void)copyText:(UIMenuController *)controller {
[self copyStorageFromIdx:0 of:controller];
}
%new
- (void)copySource:(UIMenuController *)controller {
[self copyStorageFromIdx:1 of:controller];
}
%new
- (void)copyLink:(UIMenuController *)controller {
[self copyStorageFromIdx:2 of:controller];
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
return action == @selector(copyText:) ||
action == @selector(copySource:) ||
action == @selector(copyLink:);
}
- (BOOL)canBecomeFirstResponder { return YES; }
%end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment