Browse Source

Add Apollo support

master
lint 5 years ago
parent
commit
c01a014e3c
7 changed files with 436 additions and 78 deletions
  1. +2
    -2
      Makefile
  2. +1
    -1
      control
  3. +8
    -1
      tfdidthatsay.plist
  4. +66
    -0
      tweak/Apollo.h
  5. +219
    -0
      tweak/Apollo.xm
  6. +46
    -17
      tweak/Reddit.h
  7. +94
    -57
      tweak/Reddit.xm

+ 2
- 2
Makefile View File

@@ -1,9 +1,9 @@
ARCHS = armv7 armv7s arm64 arm64e
ARCHS = arm64

include $(THEOS)/makefiles/common.mk

TWEAK_NAME = tfdidthatsay
tfdidthatsay_FILES = Tweak.xm
tfdidthatsay_FILES = $(wildcard tweak/*.xm)
#tfdidthatsay_CFLAGS = -fobjc-arc

include $(THEOS_MAKE_PATH)/tweak.mk

+ 1
- 1
control View File

@@ -1,7 +1,7 @@
Package: com.lint.undelete
Name: TFDidThatSay?
Depends: mobilesubstrate
Version: 1.1.0
Version: 1.2.0
Architecture: iphoneos-arm
Description: See "[deleted]" comments and posts without leaving Reddit!
Maintainer: lint <apieceoflint@protonmail.com>

+ 8
- 1
tfdidthatsay.plist View File

@@ -1 +1,8 @@
{ Filter = { Bundles = ( "com.reddit.Reddit" ); }; }
{
Filter = {
Bundles = (
"com.reddit.Reddit",
"com.christianselig.Apollo"
);
};
}

+ 66
- 0
tweak/Apollo.h View File

@@ -0,0 +1,66 @@
/* -- Comment Interfaces -- */
@interface RKComment
@property(assign,nonatomic) NSString* body;
@property(assign,nonatomic) NSString* bodyHTML;
@property(assign,nonatomic) NSString* author;
@property(assign,nonatomic) NSString* fullName;
@end
@interface ApolloCommentCellNode
@property(assign,nonatomic)id view;
-(BOOL) isSelected;
-(void) _layoutSublayouts;
-(void) didLoad;
-(void) calculatedLayoutDidChange;
//custom element
@property(assign,nonatomic) id undeleteButton;
@end
/* -- Post Interfaces -- */
@interface RKLink
@property(assign,nonatomic) NSString* selfText;
@property(assign,nonatomic) NSString* author;
@property(assign,nonatomic) NSString* fullName;
-(BOOL) isSelfPost;
@end
@interface ApolloCommentsHeaderCellNode
@property(assign, nonatomic) id undeleteButton;
@end
/* -- Other Interfaces -- */
@interface MarkdownRenderer
+(id) attributedStringFromMarkdown:(id) arg1 withAttributes:(id) arg2;
@end
/* -- ASyncDisplayKit Interfaces -- */
@interface _ASDisplayView : UIView
@end
@interface ASImageNode
@property(assign,nonatomic)id image;
@property(assign,nonatomic) CGRect frame;
@property(assign,nonatomic) id view;
-(CGRect)_frameInWindow;
@end
@interface ASTextNode
@property(assign,nonatomic) CGRect frame;
@property(assign,nonatomic) id attributedString;
@property(assign,nonatomic) id attributedText;
@end
@interface ApolloApolloButtonNode
@property(assign,nonatomic) NSArray* subnodes;
@end

+ 219
- 0
tweak/Apollo.xm View File

@@ -0,0 +1,219 @@
#import "Apollo.h"
%group Apollo
%hook ApolloApolloButtonNode
%end
NSDictionary* apolloBodyAttributes = nil;
%hook RKComment
-(BOOL) isDeleted{
return NO;
}
%end
%hook MarkdownRenderer
+(id) attributedStringFromHTML:(id)arg1 attributes:(id) arg2 compact:(BOOL) arg3{
apolloBodyAttributes = [arg2 copy];
return %orig;
}
%end
%hook ApolloCommentCellNode
%property(assign,nonatomic) id undeleteButton;
%new
-(void) didTapUndeleteButton{
id bodyNode = MSHookIvar<id>(self, "bodyNode");
id authorNode = MSHookIvar<id>(self, "authorNode");
id authorTextNode = [authorNode subnodes][0];
id comment = MSHookIvar<id>(self, "comment");
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/comment/?ids=%@&fields=author,body",[[comment fullName] componentsSeparatedByString:@"_"][1]]]];
[request setHTTPMethod:@"GET"];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSString *author = @"[author]";
NSString *body = @"[body]";
if (data != nil && error == nil){
id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"];
body = [[jsonData objectForKey:@"data"][0] objectForKey:@"body"];
if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){
body = @"[comment was unable to be archived]";
}
} else if (error != nil || data == nil){
body = @"[an error occured]";
}
id prevAuthorAttributedString = [authorTextNode attributedString];
NSDictionary *authorStringAttributes = [prevAuthorAttributedString attributesAtIndex:0 longestEffectiveRange:nil inRange:NSMakeRange(0, [prevAuthorAttributedString length])];
NSAttributedString* newAuthorAttributedString = [[NSAttributedString alloc] initWithString:author attributes:authorStringAttributes];
[authorTextNode setAttributedText:newAuthorAttributedString];
[authorTextNode setAttributedString:newAuthorAttributedString];
[comment setAuthor:author];
[bodyNode setAttributedString:[%c(MarkdownRenderer) attributedStringFromMarkdown:body withAttributes:apolloBodyAttributes]];
}];
}
-(void) didLoad {
%orig;
CGFloat imageSize = 20.0f;
UIButton *undeleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
[undeleteButton addTarget:self action:@selector(didTapUndeleteButton) forControlEvents:UIControlEventTouchUpInside];
undeleteButton.frame = CGRectMake(0, 0, imageSize, imageSize);
UIImage* undeleteImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
[undeleteButton setImage:undeleteImage forState:UIControlStateNormal];
[[self view] addSubview:undeleteButton];
[self setUndeleteButton:undeleteButton];
}
-(void) _layoutSublayouts{
%orig;
CGFloat imageSize = 20.0f;
id moreNode = MSHookIvar<id>(self, "moreOptionsNode");
id ageNode = MSHookIvar<id>(self, "ageNode");
CGRect nodeFrame = [moreNode frame];
CGFloat centerHeight = (nodeFrame.size.height + nodeFrame.origin.y * 2) / 2.0f;
CGFloat nodeSpacing =[ageNode frame].origin.x - nodeFrame.origin.x - nodeFrame.size.width;
[[self undeleteButton] setFrame:CGRectMake(nodeFrame.origin.x - imageSize - nodeSpacing, centerHeight - (imageSize / 2), imageSize, imageSize)];
}
%end
%hook ApolloCommentsHeaderCellNode
%property(assign, nonatomic) id undeleteButton;
%new
-(void) didTapUndeleteButton{
id bodyNode = MSHookIvar<id>(self, "bodyNode");
id postInfoNode = MSHookIvar<id>(self, "postInfoNode");
id authorNode = MSHookIvar<id>(postInfoNode, "authorButtonNode");
id authorTextNode = [authorNode subnodes][0];
id post = MSHookIvar<id>(self, "link");
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/submission/?ids=%@&fields=author,selftext",[[post fullName] componentsSeparatedByString:@"_"][1]]]];
[request setHTTPMethod:@"GET"];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSString *author = @"[author]";
NSString *body = @"[body]";
if (data != nil && error == nil){
id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"];
body = [[jsonData objectForKey:@"data"][0] objectForKey:@"selftext"];
if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){
body = @"[comment was unable to be archived]";
}
} else if (error != nil || data == nil){
body = @"[an error occured]";
}
//MSHookIvar<NSString*>(post, "_author") = author; //Crashes when clicking on author name. You will have to search the author name to go find the profile.
author = [NSString stringWithFormat:@"by %@", author];
id prevAuthorAttributedString = [authorTextNode attributedString];
NSDictionary *authorStringAttributes = [prevAuthorAttributedString attributesAtIndex:0 longestEffectiveRange:nil inRange:NSMakeRange(0, [prevAuthorAttributedString length])];
NSAttributedString* newAuthorAttributedString = [[NSAttributedString alloc] initWithString:author attributes:authorStringAttributes];
[authorTextNode setAttributedText:newAuthorAttributedString];
[authorTextNode setAttributedString:newAuthorAttributedString];
[bodyNode setAttributedString:[%c(MarkdownRenderer) attributedStringFromMarkdown:body withAttributes:apolloBodyAttributes]];
}];
}
-(void) didLoad{
%orig;
if ([MSHookIvar<id>(self, "link") isSelfPost]){
CGFloat imageSize = 20.0f;
UIButton *undeleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
[undeleteButton addTarget:self action:@selector(didTapUndeleteButton) forControlEvents:UIControlEventTouchUpInside];
UIImage* undeleteImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
[undeleteButton setImage:undeleteImage forState:UIControlStateNormal];
undeleteButton.frame = CGRectMake(0, 0, imageSize, imageSize);
[[self view] addSubview:undeleteButton];
[self setUndeleteButton:undeleteButton];
}
}
-(void) _layoutSublayouts{
%orig;
if ([self undeleteButton]){
CGFloat imageSize = 20.0f;
id postInfoNode = MSHookIvar<id>(self, "postInfoNode");
id ageNode = MSHookIvar<id>(postInfoNode, "ageButtonNode");
CGFloat centerHeight = [postInfoNode frame].origin.y + ([ageNode frame].size.height + [ageNode frame].origin.y * 2) / 2.0f;
CGFloat buttonXPos = [postInfoNode frame].origin.x + [postInfoNode frame].size.width - imageSize;
[[self undeleteButton] setFrame:CGRectMake(buttonXPos, centerHeight - (imageSize / 2), imageSize, imageSize)];
}
}
%end
%end
%ctor {
NSString* processName = [[NSProcessInfo processInfo] processName];
if ([processName isEqualToString:@"Apollo"]){
%init(Apollo, ApolloCommentsHeaderCellNode = objc_getClass("Apollo.CommentsHeaderCellNode"), ApolloCommentCellNode = objc_getClass("Apollo.CommentCellNode"), ApolloApolloButtonNode = objc_getClass("Apollo.ApolloButtonNode"));
}
}

Tweak.h → tweak/Reddit.h View File

@@ -1,12 +1,8 @@
/* -- Comment Interfaces -- */
/* ---- Reddit v4 ---- */
@interface Comment
@property(assign,nonatomic) id bodyRichTextAttributed;
@property(assign,nonatomic) id pk;
@end
/* -- Comment Interfaces -- */
@interface CommentTreeNode
@property(assign,nonatomic) id comment;
@@ -14,7 +10,6 @@
//custom elements
@property(assign,nonatomic) id commentTreeHeaderNode;
@property(assign,nonatomic) id commentTreeCommandBarNode;
@property(assign,nonatomic) BOOL isLoadingArchivedComment;
@end
@interface CommentTreeDisplayNode
@@ -44,10 +39,8 @@
-(id)animationControllerForDismissedController:(id) arg1;
@end
/* -- Post Interfaces -- */
@interface Post
@property(assign,nonatomic) id author;
@property(assign,nonatomic) BOOL isSelfPost;
@@ -118,22 +111,58 @@
+(id) sharedSettings;
@end
/* -- ActivityIndicator Interfaces -- */
@interface AccountManager
@property(assign,nonatomic) id defaults;
+(id) sharedManager;
@end
/* ---- Reddit v3 ---- */
/* -- Comment Interfaces -- */
@interface CommentCell : UIView
-(id) delegate;
-(id) comment;
-(id) commentView;
@end
@interface CommentView
-(void) configureSubviews;
-(void) layoutSubviews;
-(id) commandView;
-(id) comment;
-(id) delegate;
@end
@interface _ASCollectionViewCell
@property(assign,nonatomic) id node;
@interface CommentCommandView
@property (nonatomic, assign) id undeleteButton;
-(id)overflowButton;
-(id) comment;
-(id) delegate;
@end
@interface CellDisplayNodeWrapper
@property(assign,nonatomic) id contentNode;
@interface CommentsViewController
-(void) reloadCommentsWithNewCommentsHighlight:(BOOL) arg1 autoScroll:(BOOL) arg2 animated:(BOOL) arg3;
-(void)updateFloatingViews;
@end
/* -- Other Interfaces -- */
@interface MarkDownParser
+(id)attributedStringFromMarkdownString:(id)arg1;
@end
/* ---- Reddit v3 & v4 ---- */
@interface Comment
//v4
@property(assign,nonatomic) id bodyRichTextAttributed;
@property(assign,nonatomic) id pk;
//v3
-(id)pkWithoutPrefix;
@end

Tweak.xm → tweak/Reddit.xm View File

@@ -1,12 +1,11 @@
#include "Tweak.h"
#import "Reddit.h"
%group Redditv4
%hook CommentTreeNode
%property(assign,nonatomic)id commentTreeHeaderNode;
%property(assign,nonatomic)id commentTreeCommandBarNode;
%property(assign,nonatomic)BOOL isLoadingArchivedComment;
%end
@@ -28,37 +27,10 @@
%orig;
[[self commentTreeNode] setCommentTreeCommandBarNode:self];
[[self commentTreeNode] setIsLoadingArchivedComment:NO];
}
%end
/*
%hook ASCollectionView
-(id) dequeueReusableCellWithReuseIdentifier: (id) arg1 forIndexPath:(id) arg2{
id orig = %orig;
if ([orig isKindOfClass:[%c(_ASCollectionViewCell) class]]){
id node = [[orig node] contentNode];
if ([node isKindOfClass:[%c(CommentTreeDisplayNode) class]]) {
id commentNode = [node commentNode];
if ([commentNode isLoadingArchivedComment]){
//[[[commentNode commentTreeCommandBarNode] activityIndicator] startAnimating];
}
}
}
return orig;
}
%end
*/
%hook CommentActionSheetViewController
-(void) setItems:(id) arg1{
@@ -87,20 +59,6 @@
id commentTreeNode = [self commentTreeNode];
id comment = [commentTreeNode comment];
[commentTreeNode setIsLoadingArchivedComment:YES];
/*
id isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
if (isNightMode){
UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
} else {
UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
}
[self setActivityIndicator:activityIndicator];
[activityIndicator startAnimating];
[sender addSubview:activityIndicator];
*/
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
@@ -147,9 +105,6 @@
}];
[bodyMutableAttributedText endEditing];
[comment setValue:bodyMutableAttributedText forKey:@"bodyRichTextAttributed"];
@@ -159,11 +114,7 @@
[comment setValue:bodyMutableAttributedText forKey:@"bodyAttributedText"];
[[commentTreeNode commentTreeHeaderNode] updateContentViewsForData:comment];
[commentTreeNode setIsLoadingArchivedComment:NO];
//[activityIndicator stopAnimating];
[request release];
[queue release];
[bodyMutableAttributedText release];
@@ -294,18 +245,104 @@
%group Redditv3
%hook CommentView
%new
-(void) buttonAction {
id commentsViewController = [self delegate];
id comment = [self comment];
NSError* error;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/comment/?ids=%@&fields=author,body",[comment pkWithoutPrefix]]]];
[request setHTTPMethod:@"GET"];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
NSString *author = @"[author]";
NSString *body = @"[body]";
if (data != nil && error == nil){
id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"];
body = [[jsonData objectForKey:@"data"][0] objectForKey:@"body"];
if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){
body = @"[comment was unable to be archived]";
}
} else if (error != nil || data == nil){
body = @"[an error occured]";
}
[comment setValue:author forKey:@"author"];
[comment setValue:[%c(MarkDownParser) attributedStringFromMarkdownString: body] forKey:@"bodyAttributedText"];
[comment setValue:body forKey:@"bodyText"];
[commentsViewController reloadCommentsWithNewCommentsHighlight:NO autoScroll:NO animated:NO];
}
-(id) initWithFrame:(id)arg1{
id orig = %orig;
id commandView = [self commandView];
UIButton *undeleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
[undeleteButton addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
UIImage* undeleteImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
[undeleteButton setImage:undeleteImage forState:UIControlStateNormal];
[commandView setUndeleteButton:undeleteButton];
[commandView addSubview:undeleteButton];
return orig;
}
%end
%hook CommentCommandView
%property (assign, nonatomic) id undeleteButton;
-(void) layoutSubviews{
%orig;
UIButton *button = [self undeleteButton];
button.frame = CGRectMake([[self overflowButton ] frame].origin.x - 32, 0, 32, 32);
}
%end
%end
%ctor{
NSString* processName = [[NSProcessInfo processInfo] processName];
NSString* version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
NSArray* versionArray = [version componentsSeparatedByString:@"."];
if ([versionArray[0] isEqualToString:@"4"]){
%init(Redditv4);
} else if ([versionArray[0] isEqualToString:@"3"]) {
if ([processName isEqualToString:@"Reddit"]){
if ([versionArray[0] isEqualToString:@"4"]){
%init(Redditv4);
} else if ([versionArray[0] isEqualToString:@"3"]) {
%init(Redditv3);
}
}
}

Loading…
Cancel
Save