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.

254 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. id prevAuthorAttributedString = [authorTextNode attributedString];
  66. NSDictionary *authorStringAttributes = [prevAuthorAttributedString attributesAtIndex:0 longestEffectiveRange:nil inRange:NSMakeRange(0, [prevAuthorAttributedString length])];
  67. NSAttributedString *newAuthorAttributedString = [[NSAttributedString alloc] initWithString:author attributes:authorStringAttributes];
  68. [authorTextNode setAttributedText:newAuthorAttributedString];
  69. [authorTextNode setAttributedString:newAuthorAttributedString];
  70. [comment setAuthor:author];
  71. [bodyNode setAttributedString:[%c(MarkdownRenderer) attributedStringFromMarkdown:data[@"body"] withAttributes:apolloBodyAttributes]];
  72. [data[@"sender"] setEnabled:YES];
  73. }
  74. %end
  75. %hook ApolloCommentsHeaderCellNode
  76. %property(strong, nonatomic) id undeleteButton;
  77. -(void) didLoad{
  78. %orig;
  79. id post = MSHookIvar<id>(self, "link");
  80. id postBody = [post selfText];
  81. if ([post isSelfPost]){
  82. if ([%c(TFHelper) shouldShowUndeleteButtonWithInfo:postBody isDeletedOnly:isTFDeletedOnly]){
  83. CGFloat imageSize = 20.0f;
  84. UIButton *undeleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
  85. [undeleteButton addTarget:self action:@selector(didTapUndeleteButton:) forControlEvents:UIControlEventTouchUpInside];
  86. UIImage* undeleteImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  87. [undeleteButton setImage:undeleteImage forState:UIControlStateNormal];
  88. undeleteButton.frame = CGRectMake(0, 0, imageSize, imageSize);
  89. [[self view] addSubview:undeleteButton];
  90. [self setUndeleteButton:undeleteButton];
  91. }
  92. }
  93. }
  94. -(void) _layoutSublayouts{
  95. %orig;
  96. if ([self undeleteButton]){
  97. CGFloat imageSize = 20.0f;
  98. id postInfoNode = MSHookIvar<id>(self, "postInfoNode");
  99. id ageNode = MSHookIvar<id>(postInfoNode, "ageButtonNode");
  100. CGFloat centerHeight = [postInfoNode frame].origin.y + ([ageNode frame].size.height + [ageNode frame].origin.y * 2) / 2.0f;
  101. CGFloat buttonXPos = [postInfoNode frame].origin.x + [postInfoNode frame].size.width - imageSize;
  102. [[self undeleteButton] setFrame:CGRectMake(buttonXPos, centerHeight - (imageSize / 2), imageSize, imageSize)];
  103. }
  104. }
  105. %new
  106. -(void) didTapUndeleteButton:(id) sender{
  107. [sender setEnabled:NO];
  108. id post = MSHookIvar<id>(self, "link");
  109. [%c(TFHelper) getUndeleteDataWithID:[[post fullName] componentsSeparatedByString:@"_"][1] isComment:NO timeout:pushshiftRequestTimeoutValue extraData:@{@"sender" : sender} completionTarget:self completionSelector:@selector(completeUndeletePostAction:)];
  110. }
  111. %new
  112. -(void) completeUndeletePostAction:(NSDictionary *) data{
  113. id bodyNode = MSHookIvar<id>(self, "bodyNode");
  114. id postInfoNode = MSHookIvar<id>(self, "postInfoNode");
  115. id authorNode = MSHookIvar<id>(postInfoNode, "authorButtonNode");
  116. id authorTextNode = [authorNode subnodes][0];
  117. NSString *author = data[@"author"];
  118. //id post = MSHookIvar<id>(self, "link");
  119. //MSHookIvar<NSString*>(post, "_author") = author; //Crashes when clicking on author name. You will have to search the author name to go find the profile.
  120. author = [NSString stringWithFormat:@"by %@", author];
  121. id prevAuthorAttributedString = [authorTextNode attributedString];
  122. NSDictionary *authorStringAttributes = [prevAuthorAttributedString attributesAtIndex:0 longestEffectiveRange:nil inRange:NSMakeRange(0, [prevAuthorAttributedString length])];
  123. NSAttributedString* newAuthorAttributedString = [[NSAttributedString alloc] initWithString:author attributes:authorStringAttributes];
  124. [authorTextNode setAttributedText:newAuthorAttributedString];
  125. [authorTextNode setAttributedString:newAuthorAttributedString];
  126. [bodyNode setAttributedString:[%c(MarkdownRenderer) attributedStringFromMarkdown:data[@"body"] withAttributes:apolloBodyAttributes]];
  127. [data[@"sender"] setEnabled:YES];
  128. }
  129. %end
  130. %end
  131. static void loadPrefs(){
  132. NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/User/Library/Preferences/com.lint.undelete.prefs.plist"];
  133. if (prefs){
  134. if ([prefs objectForKey:@"isApolloEnabled"] != nil) {
  135. isApolloEnabled = [[prefs objectForKey:@"isApolloEnabled"] boolValue];
  136. } else {
  137. isApolloEnabled = YES;
  138. }
  139. if ([prefs objectForKey:@"isTFDeletedOnly"] != nil) {
  140. isTFDeletedOnly = [[prefs objectForKey:@"isTFDeletedOnly"] boolValue];
  141. } else {
  142. isTFDeletedOnly = YES;
  143. }
  144. if ([prefs objectForKey:@"requestTimeoutValue"] != nil){
  145. pushshiftRequestTimeoutValue = [[prefs objectForKey:@"requestTimeoutValue"] doubleValue];
  146. } else {
  147. pushshiftRequestTimeoutValue = 10;
  148. }
  149. } else {
  150. isApolloEnabled = YES;
  151. isTFDeletedOnly = YES;
  152. pushshiftRequestTimeoutValue = 10;
  153. }
  154. }
  155. static void prefsChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
  156. loadPrefs();
  157. }
  158. %ctor {
  159. loadPrefs();
  160. NSString* processName = [[NSProcessInfo processInfo] processName];
  161. if ([processName isEqualToString:@"Apollo"]){
  162. if (isApolloEnabled){
  163. CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, prefsChanged, CFSTR("com.lint.undelete.prefs.changed"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
  164. %init(Apollo, ApolloCommentsHeaderCellNode = objc_getClass("Apollo.CommentsHeaderCellNode"), ApolloCommentCellNode = objc_getClass("Apollo.CommentCellNode"), ApolloApolloButtonNode = objc_getClass("Apollo.ApolloButtonNode"));
  165. }
  166. }
  167. }