You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
8.2KB

  1. #import "Apollo.h"
  2. #import "assets/TFHelper.h"
  3. static BOOL isTFDeletedOnly;
  4. static BOOL isApolloEnabled;
  5. static CGFloat pushshiftRequestTimeoutValue;
  6. %group Apollo
  7. NSDictionary* apolloBodyAttributes = nil;
  8. %hook ApolloApolloButtonNode
  9. %end
  10. %hook RKComment
  11. -(BOOL) isDeleted{
  12. return NO;
  13. }
  14. -(BOOL) isModeratorRemoved{
  15. return NO;
  16. }
  17. %end
  18. %hook MarkdownRenderer
  19. +(id) attributedStringFromHTML:(id)arg1 attributes:(id) arg2 compact:(BOOL) arg3{
  20. apolloBodyAttributes = [arg2 copy];
  21. return %orig;
  22. }
  23. %end
  24. %hook ApolloCommentCellNode
  25. %property(strong,nonatomic) id undeleteButton;
  26. -(void) didLoad {
  27. %orig;
  28. id commentBody = [MSHookIvar<id>(self, "comment") body];
  29. if ([%c(TFHelper) shouldShowUndeleteButtonWithInfo:commentBody isDeletedOnly:isTFDeletedOnly]){
  30. CGFloat imageSize = 20.0f;
  31. UIButton *undeleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
  32. [undeleteButton addTarget:self action:@selector(didTapUndeleteButton:) forControlEvents:UIControlEventTouchUpInside];
  33. undeleteButton.frame = CGRectMake(0, 0, imageSize, imageSize);
  34. UIImage* undeleteImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  35. [undeleteButton setImage:undeleteImage forState:UIControlStateNormal];
  36. [[self view] addSubview:undeleteButton];
  37. [self setUndeleteButton:undeleteButton];
  38. }
  39. }
  40. -(void) _layoutSublayouts{
  41. %orig;
  42. if ([self undeleteButton]){
  43. CGFloat imageSize = 20.0f;
  44. id moreNode = MSHookIvar<id>(self, "moreOptionsNode");
  45. id ageNode = MSHookIvar<id>(self, "ageNode");
  46. CGRect nodeFrame = [moreNode frame];
  47. CGFloat centerHeight = (nodeFrame.size.height + nodeFrame.origin.y * 2) / 2.0f;
  48. CGFloat nodeSpacing =[ageNode frame].origin.x - nodeFrame.origin.x - nodeFrame.size.width;
  49. [[self undeleteButton] setFrame:CGRectMake(nodeFrame.origin.x - imageSize - nodeSpacing, centerHeight - (imageSize / 2), imageSize, imageSize)];
  50. }
  51. }
  52. %new
  53. -(void) didTapUndeleteButton:(id) sender{
  54. [sender setEnabled:NO];
  55. id comment = MSHookIvar<id>(self, "comment");
  56. [%c(TFHelper) getUndeleteDataWithID:[[comment fullName] componentsSeparatedByString:@"_"][1] isComment:YES timeout:pushshiftRequestTimeoutValue extraData:@{@"sender" : sender} completionTarget:self completionSelector:@selector(completeUndeleteCommentAction:)];
  57. }
  58. %new
  59. -(void) completeUndeleteCommentAction:(NSDictionary *) data{
  60. id comment = MSHookIvar<id>(self, "comment");
  61. id bodyNode = MSHookIvar<id>(self, "bodyNode");
  62. id authorNode = MSHookIvar<id>(self, "authorNode");
  63. id authorTextNode = [authorNode subnodes][0];
  64. NSString *author = data[@"author"];
  65. NSString *body = data[@"body"];
  66. id prevAuthorAttributedString = [authorTextNode attributedString];
  67. NSDictionary *authorStringAttributes = [prevAuthorAttributedString attributesAtIndex:0 longestEffectiveRange:nil inRange:NSMakeRange(0, [prevAuthorAttributedString length])];
  68. NSAttributedString *newAuthorAttributedString = [[NSAttributedString alloc] initWithString:author attributes:authorStringAttributes];
  69. [authorTextNode setAttributedText:newAuthorAttributedString];
  70. [authorTextNode setAttributedString:newAuthorAttributedString];
  71. [bodyNode setAttributedString:[%c(MarkdownRenderer) attributedStringFromMarkdown:body withAttributes:apolloBodyAttributes]];
  72. [comment setAuthor:author];
  73. [comment setBody:body];
  74. [data[@"sender"] setEnabled:YES];
  75. }
  76. %end
  77. %hook ApolloCommentsHeaderCellNode
  78. %property(strong, nonatomic) id undeleteButton;
  79. -(void) didLoad{
  80. %orig;
  81. id post = MSHookIvar<id>(self, "link");
  82. id postBody = [post selfText];
  83. if ([post isSelfPost]){
  84. if ([%c(TFHelper) shouldShowUndeleteButtonWithInfo:postBody isDeletedOnly:isTFDeletedOnly]){
  85. CGFloat imageSize = 20.0f;
  86. UIButton *undeleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
  87. [undeleteButton addTarget:self action:@selector(didTapUndeleteButton:) forControlEvents:UIControlEventTouchUpInside];
  88. UIImage* undeleteImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  89. [undeleteButton setImage:undeleteImage forState:UIControlStateNormal];
  90. undeleteButton.frame = CGRectMake(0, 0, imageSize, imageSize);
  91. [[self view] addSubview:undeleteButton];
  92. [self setUndeleteButton:undeleteButton];
  93. }
  94. }
  95. }
  96. -(void) _layoutSublayouts{
  97. %orig;
  98. if ([self undeleteButton]){
  99. CGFloat imageSize = 20.0f;
  100. id postInfoNode = MSHookIvar<id>(self, "postInfoNode");
  101. id ageNode = MSHookIvar<id>(postInfoNode, "ageButtonNode");
  102. CGFloat centerHeight = [postInfoNode frame].origin.y + ([ageNode frame].size.height + [ageNode frame].origin.y * 2) / 2.0f;
  103. CGFloat buttonXPos = [postInfoNode frame].origin.x + [postInfoNode frame].size.width - imageSize;
  104. [[self undeleteButton] setFrame:CGRectMake(buttonXPos, centerHeight - (imageSize / 2), imageSize, imageSize)];
  105. }
  106. }
  107. %new
  108. -(void) didTapUndeleteButton:(id) sender{
  109. [sender setEnabled:NO];
  110. id post = MSHookIvar<id>(self, "link");
  111. [%c(TFHelper) getUndeleteDataWithID:[[post fullName] componentsSeparatedByString:@"_"][1] isComment:NO timeout:pushshiftRequestTimeoutValue extraData:@{@"sender" : sender} completionTarget:self completionSelector:@selector(completeUndeletePostAction:)];
  112. }
  113. %new
  114. -(void) completeUndeletePostAction:(NSDictionary *) data{
  115. id bodyNode = MSHookIvar<id>(self, "bodyNode");
  116. id postInfoNode = MSHookIvar<id>(self, "postInfoNode");
  117. id authorNode = MSHookIvar<id>(postInfoNode, "authorButtonNode");
  118. id authorTextNode = [authorNode subnodes][0];
  119. NSString *author = data[@"author"];
  120. //id post = MSHookIvar<id>(self, "link");
  121. //MSHookIvar<NSString*>(post, "_author") = author; //Crashes when clicking on author name. You will have to search the author name to go find the profile.
  122. author = [NSString stringWithFormat:@"by %@", author];
  123. id prevAuthorAttributedString = [authorTextNode attributedString];
  124. NSDictionary *authorStringAttributes = [prevAuthorAttributedString attributesAtIndex:0 longestEffectiveRange:nil inRange:NSMakeRange(0, [prevAuthorAttributedString length])];
  125. NSAttributedString* newAuthorAttributedString = [[NSAttributedString alloc] initWithString:author attributes:authorStringAttributes];
  126. [authorTextNode setAttributedText:newAuthorAttributedString];
  127. [authorTextNode setAttributedString:newAuthorAttributedString];
  128. [bodyNode setAttributedString:[%c(MarkdownRenderer) attributedStringFromMarkdown:data[@"body"] withAttributes:apolloBodyAttributes]];
  129. [data[@"sender"] setEnabled:YES];
  130. }
  131. %end
  132. %end
  133. static void loadPrefs(){
  134. NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/User/Library/Preferences/com.lint.undelete.prefs.plist"];
  135. if (prefs){
  136. if ([prefs objectForKey:@"isApolloEnabled"] != nil) {
  137. isApolloEnabled = [[prefs objectForKey:@"isApolloEnabled"] boolValue];
  138. } else {
  139. isApolloEnabled = YES;
  140. }
  141. if ([prefs objectForKey:@"isTFDeletedOnly"] != nil) {
  142. isTFDeletedOnly = [[prefs objectForKey:@"isTFDeletedOnly"] boolValue];
  143. } else {
  144. isTFDeletedOnly = YES;
  145. }
  146. if ([prefs objectForKey:@"requestTimeoutValue"] != nil){
  147. pushshiftRequestTimeoutValue = [[prefs objectForKey:@"requestTimeoutValue"] doubleValue];
  148. } else {
  149. pushshiftRequestTimeoutValue = 10;
  150. }
  151. } else {
  152. isApolloEnabled = YES;
  153. isTFDeletedOnly = YES;
  154. pushshiftRequestTimeoutValue = 10;
  155. }
  156. }
  157. static void prefsChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
  158. loadPrefs();
  159. }
  160. %ctor {
  161. loadPrefs();
  162. NSString* processName = [[NSProcessInfo processInfo] processName];
  163. if ([processName isEqualToString:@"Apollo"]){
  164. if (isApolloEnabled){
  165. CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, prefsChanged, CFSTR("com.lint.undelete.prefs.changed"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
  166. %init(Apollo, ApolloCommentsHeaderCellNode = objc_getClass("Apollo.CommentsHeaderCellNode"), ApolloCommentCellNode = objc_getClass("Apollo.CommentCellNode"), ApolloApolloButtonNode = objc_getClass("Apollo.ApolloButtonNode"));
  167. }
  168. }
  169. }