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.

преди 5 години
преди 5 години
преди 4 години
преди 5 години
преди 5 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 4 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 4 години
преди 5 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 5 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 5 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 5 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 5 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 5 години
преди 4 години
преди 4 години
преди 5 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. #import "Slide.h"
  2. #import "assets/TFHelper.h"
  3. #import "assets/MMMarkdown/MMMarkdown.h"
  4. static BOOL isEnabled;
  5. static BOOL isSlideEnabled;
  6. static BOOL isTFDeletedOnly;
  7. static CGFloat pushshiftRequestTimeoutValue;
  8. %group Slide
  9. BOOL shouldSlideOverridePostInfo = NO;
  10. NSString *slidePostOverrideAuthor;
  11. NSString *slidePostOverrideBodyHtml;
  12. @implementation FontGenerator
  13. + (UIFont *)fontOfSize:(CGFloat)size submission:(BOOL)isSubmission willOffset:(BOOL)willOffset {
  14. NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  15. NSString *fontName;
  16. CGFloat fontSize = size;
  17. if (willOffset) {
  18. if (isSubmission){
  19. fontSize += ([userDefaults objectForKey:@"POST_FONT_SIZE"] == nil) ? 0 : [userDefaults integerForKey:@"POST_FONT_SIZE"];
  20. } else {
  21. fontSize += ([userDefaults objectForKey:@"COMMENT_FONT_SIZE"] == nil) ? -2 : [userDefaults integerForKey:@"COMMENT_FONT_SIZE"];
  22. }
  23. }
  24. if ([userDefaults stringForKey:(isSubmission ? @"postfont" : @"commentfont")] == nil) {
  25. fontName = isSubmission ? @"AvenirNext-DemiBold" : @"AvenirNext-Medium";
  26. } else {
  27. fontName = [userDefaults stringForKey:(isSubmission ? @"postfont" : @"commentfont")];
  28. }
  29. UIFont *font = [UIFont fontWithName:fontName size:fontSize];
  30. if (!font) {
  31. font = [UIFont systemFontOfSize:fontSize];
  32. }
  33. return font;
  34. }
  35. + (UIFont *)boldFontOfSize:(CGFloat)size submission:(BOOL)isSubmission willOffset:(BOOL)willOffset {
  36. UIFont *font = [self fontOfSize:size submission:isSubmission willOffset:willOffset];
  37. if ([font.fontName isEqualToString:[UIFont systemFontOfSize:10].fontName]){
  38. return [UIFont boldSystemFontOfSize:font.pointSize];
  39. } else {
  40. UIFontDescriptor *desc = [font.fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
  41. if (desc == nil){
  42. return font;
  43. } else {
  44. return [UIFont fontWithDescriptor:desc size: 0];
  45. }
  46. }
  47. }
  48. + (UIFont *)italicFontOfSize:(CGFloat)size submission:(BOOL)isSubmission willOffset:(BOOL)willOffset {
  49. UIFont *font = [self fontOfSize:size submission:isSubmission willOffset:willOffset];
  50. if ([font.fontName isEqualToString:[UIFont systemFontOfSize:10].fontName]) {
  51. return [UIFont italicSystemFontOfSize:font.pointSize];
  52. } else {
  53. UIFontDescriptor *desc = [font.fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic];
  54. if (desc == nil) {
  55. return font;
  56. } else {
  57. return [UIFont fontWithDescriptor:desc size: 0];
  58. }
  59. }
  60. }
  61. @end
  62. @implementation ColorUtil
  63. + (UIColor *)accentColorForSub:(NSString *)subreddit {
  64. NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  65. NSData *colorData = [userDefaults dataForKey:[NSString stringWithFormat:@"accent+%@", subreddit]];
  66. //UIColor *color = [NSKeyedUnarchiver unarchiveObjectWithData:colorData]; // deprecated
  67. UIColor *color = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIColor class] fromData:colorData error:nil];
  68. if (color) {
  69. return color;
  70. } else {
  71. //UIColor *baseAccentColor = [NSKeyedUnarchiver unarchiveObjectWithData:[userDefaults dataForKey:@"accentcolor"]]; // deprecated
  72. UIColor *baseAccentColor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIColor class] fromData:[userDefaults dataForKey:@"accentcolor"] error:nil];
  73. if (baseAccentColor) {
  74. return baseAccentColor;
  75. } else {
  76. return [UIColor colorWithRed:0.161 green:0.475 blue:1.0 alpha:1.0];
  77. }
  78. }
  79. }
  80. + (UIColor *)fontColorForTheme:(NSString *)theme {
  81. UIColor *fontColor;
  82. NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  83. //if only switch blocks worked with strings...
  84. if ([theme isEqualToString:@"light"]) {
  85. fontColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.87];
  86. } else if ([theme isEqualToString:@"dark"]) {
  87. fontColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.87];
  88. } else if ([theme isEqualToString:@"black"]) {
  89. fontColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.87];
  90. } else if ([theme isEqualToString:@"blue"]) {
  91. fontColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.87];
  92. } else if ([theme isEqualToString:@"sepia"]) {
  93. fontColor = [UIColor colorWithRed:0.243 green:.239 blue:.212 alpha:0.87];
  94. } else if ([theme isEqualToString:@"red"]) {
  95. fontColor = [UIColor colorWithRed:1.0 green:0.969 blue:0.929 alpha:0.87];
  96. } else if ([theme isEqualToString:@"deep"]) {
  97. fontColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.87];
  98. } else if ([theme isEqualToString:@"mint"]) {
  99. fontColor = [UIColor colorWithRed:0.035 green:0.212 blue:0.059 alpha:0.87];
  100. } else if ([theme isEqualToString:@"cream"]) {
  101. fontColor = [UIColor colorWithRed:0.267 green:0.255 blue:0.224 alpha:0.87];
  102. } else if ([theme isEqualToString:@"acontrast"]) {
  103. fontColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.87];
  104. } else if ([theme isEqualToString:@"pink"]) {
  105. fontColor = [UIColor colorWithRed:0.149 green:0.157 blue:0.267 alpha:0.87];
  106. } else if ([theme isEqualToString:@"solarize"]) {
  107. fontColor = [UIColor colorWithRed:0.514 green:0.580 blue:0.588 alpha:0.87];
  108. } else if (!theme) {
  109. fontColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.87];
  110. } else {
  111. NSString *customThemeString = [[userDefaults stringForKey:[NSString stringWithFormat:@"Theme+%@", theme]] stringByRemovingPercentEncoding];
  112. if (customThemeString) {
  113. NSString *customFontColorHex = [customThemeString componentsSeparatedByString:@"#"][4];
  114. fontColor = [UIColor colorWithHex:customFontColorHex];
  115. } else {
  116. fontColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.87];
  117. }
  118. }
  119. return fontColor;
  120. }
  121. + (UIColor *)backgroundColorForTheme:(NSString *)theme {
  122. UIColor *backgroundColor;
  123. NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  124. if ([theme isEqualToString:@"light"]) {
  125. backgroundColor = [UIColor colorWithRed:0.352 green:0.352 blue:0.352 alpha:1.0];
  126. } else if ([theme isEqualToString:@"dark"]) {
  127. backgroundColor = [UIColor colorWithRed:0.051 green:0.051 blue:0.051 alpha:1.0];
  128. } else if ([theme isEqualToString:@"black"]) {
  129. backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:1.0];
  130. } else if ([theme isEqualToString:@"blue"]) {
  131. backgroundColor = [UIColor colorWithRed:0.071 green:0.094 blue:0.106 alpha:1.0];
  132. } else if ([theme isEqualToString:@"sepia"]) {
  133. backgroundColor = [UIColor colorWithRed:0.310 green:0.302 blue:0.267 alpha:1.0];
  134. } else if ([theme isEqualToString:@"red"]) {
  135. backgroundColor = [UIColor colorWithRed:0.075 green:0.055 blue:0.051 alpha:1.0];
  136. } else if ([theme isEqualToString:@"deep"]) {
  137. backgroundColor = [UIColor colorWithRed:0.035 green:0.035 blue:0.043 alpha:1.0];
  138. } else if ([theme isEqualToString:@"mint"]) {
  139. backgroundColor = [UIColor colorWithRed:0.364 green:0.376 blue:0.357 alpha:1.0];
  140. } else if ([theme isEqualToString:@"cream"]) {
  141. backgroundColor = [UIColor colorWithRed:0.322 green:0.314 blue:0.286 alpha:1.0];
  142. } else if ([theme isEqualToString:@"acontrast"]) {
  143. backgroundColor = [UIColor colorWithRed:0.027 green:0.027 blue:0.24 alpha:1.0];
  144. } else if ([theme isEqualToString:@"pink"]) {
  145. backgroundColor = [UIColor colorWithRed:1.0 green:0.376 blue:0.357 alpha:1.0];
  146. } else if ([theme isEqualToString:@"solarize"]) {
  147. backgroundColor = [UIColor colorWithRed:0.040 green:0.067 blue:0.082 alpha:1.0];
  148. } else if (!theme) {
  149. backgroundColor = [UIColor colorWithRed:0.352 green:0.352 blue:0.352 alpha:1.0];
  150. } else {
  151. NSString *customThemeString = [[userDefaults stringForKey:[NSString stringWithFormat:@"Theme+%@", theme]] stringByRemovingPercentEncoding];
  152. if (customThemeString) {
  153. NSString *customFontColorHex = [customThemeString componentsSeparatedByString:@"#"][3];
  154. backgroundColor = [UIColor colorWithHex:customFontColorHex];
  155. } else {
  156. backgroundColor = [UIColor colorWithRed:0.352 green:0.352 blue:0.352 alpha:1.0];
  157. }
  158. }
  159. return backgroundColor;
  160. }
  161. @end
  162. static UIButton *createUndeleteButton(){
  163. UIButton *undeleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
  164. UIImage *undeleteImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160white.png"];
  165. UIGraphicsBeginImageContextWithOptions(CGSizeMake(20, 20), NO, 0);
  166. [undeleteImage drawInRect:CGRectMake(0, 0, 20, 20)];
  167. undeleteImage = UIGraphicsGetImageFromCurrentImageContext();
  168. UIGraphicsEndImageContext();
  169. UIGraphicsBeginImageContextWithOptions(CGSizeMake(35, 35), NO, 0);
  170. CGContextRef context = UIGraphicsGetCurrentContext();
  171. UIGraphicsPushContext(context);
  172. [undeleteImage drawAtPoint:CGPointMake(7.5, 7.5)];
  173. UIGraphicsPopContext();
  174. undeleteImage = UIGraphicsGetImageFromCurrentImageContext();
  175. UIGraphicsEndImageContext();
  176. [undeleteButton setImage:undeleteImage forState:UIControlStateNormal];
  177. undeleteButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
  178. return undeleteButton;
  179. }
  180. %hook UIColor
  181. %new
  182. + (UIColor *)colorWithHex:(NSString *)arg1 {
  183. if (!arg1){
  184. NSString *firstChar = [arg1 substringToIndex:1];
  185. if ([firstChar isEqualToString:@"#"]){
  186. arg1 = [arg1 substringWithRange:NSMakeRange(1, [arg1 length]-1)];
  187. }
  188. unsigned rgbValue = 0;
  189. NSScanner *scanner = [NSScanner scannerWithString:arg1];
  190. [scanner scanHexInt:&rgbValue];
  191. return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:0.87];
  192. } else {
  193. return nil;
  194. }
  195. }
  196. %new
  197. - (NSString *)hexString {
  198. const CGFloat *components = CGColorGetComponents(self.CGColor);
  199. CGFloat r = components[0];
  200. CGFloat g = components[1];
  201. CGFloat b = components[2];
  202. return [NSString stringWithFormat:@"#%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255)];
  203. }
  204. %end
  205. %hook CommentDepthCell
  206. - (void)doShortClick {
  207. %orig;
  208. [self addUndeleteButtonToMenu];
  209. }
  210. - (void)doLongClick {
  211. %orig;
  212. [self addUndeleteButtonToMenu];
  213. }
  214. %new
  215. - (void)addUndeleteButtonToMenu {
  216. NSString *author = [MSHookIvar<id>(self, "comment") author];
  217. if ([%c(TFHelper) shouldShowUndeleteButtonWithInfo:author isDeletedOnly:isTFDeletedOnly]) {
  218. id controller = MSHookIvar<id>(self, "parent");
  219. if (MSHookIvar<id>(controller, "menuCell")) {
  220. UIStackView *menu = MSHookIvar<UIStackView *>(self, "menu");
  221. if (![[[[menu arrangedSubviews] lastObject] actionsForTarget:self forControlEvent:UIControlEventTouchUpInside] containsObject:@"handleUndeleteComment:"]) {
  222. UIButton *undeleteButton = createUndeleteButton();
  223. [undeleteButton addTarget:self action:@selector(handleUndeleteComment:) forControlEvents:UIControlEventTouchUpInside];
  224. [menu addArrangedSubview:undeleteButton];
  225. }
  226. }
  227. }
  228. }
  229. %new
  230. - (void)handleUndeleteComment:(id)sender {
  231. [sender setEnabled:NO];
  232. id comment = MSHookIvar<id>(self, "comment");
  233. [%c(TFHelper) getUndeleteDataWithID:[[comment id] componentsSeparatedByString:@"_"][1] isComment:YES timeout:pushshiftRequestTimeoutValue extraData:@{@"sender" : sender} completionTarget:self completionSelector:@selector(completeUndeleteCommentAction:)];
  234. }
  235. %new
  236. - (void)completeUndeleteCommentAction:(NSDictionary *)data {
  237. NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  238. id textStackDisplayView = MSHookIvar<id>(self, "commentBody");
  239. id comment = MSHookIvar<id>(self, "comment");
  240. NSString *author = data[@"author"];
  241. NSString *body = data[@"body"];
  242. //Attributed string generation rewrote from Slide_for_Reddit.TextDisplayStackView.createAttributedChunk(...)
  243. UIFont *font = [%c(FontGenerator) fontOfSize:MSHookIvar<CGFloat>(textStackDisplayView, "fontSize") submission:NO willOffset:YES];
  244. NSString *themeName = [userDefaults stringForKey:@"theme"];
  245. UIColor *fontColor = [%c(ColorUtil) fontColorForTheme:themeName];
  246. UIColor *accentColor = [%c(ColorUtil) accentColorForSub:[comment subreddit]];
  247. NSString *html = [%c(MMMarkdown) HTMLStringWithMarkdown:body extensions:MMMarkdownExtensionsGitHubFlavored error:nil];
  248. html = [[html stringByReplacingOccurrencesOfString:@"<sup>" withString:@"<font size=\"1\">"] stringByReplacingOccurrencesOfString:@"</sup>" withString:@"</font>"];
  249. html = [[html stringByReplacingOccurrencesOfString:@"<del>" withString:@"<font color=\"green\">"] stringByReplacingOccurrencesOfString:@"</del>" withString:@"</font>"];
  250. html = [[html stringByReplacingOccurrencesOfString:@"<code>" withString:@"<font color=\"blue\">"] stringByReplacingOccurrencesOfString:@"</code>" withString:@"</font>"];
  251. html = [html stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  252. DTHTMLAttributedStringBuilder *dthtmlBuilder = [[%c(DTHTMLAttributedStringBuilder) alloc] initWithHTML:[html dataUsingEncoding:NSUTF8StringEncoding] options:@{@"DTUseiOS6Attributes": @YES, @"DTDefaultTextColor": fontColor, @"DTDefaultFontSize": @([font pointSize])} documentAttributes:nil];
  253. NSMutableAttributedString *htmlAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:[dthtmlBuilder generatedAttributedString]];
  254. NSRange htmlStringRange = NSMakeRange(0, [htmlAttributedString length]);
  255. [[htmlAttributedString mutableString] replaceOccurrencesOfString:@"\t•\t" withString:@" • " options:0 range: htmlStringRange];
  256. [[htmlAttributedString mutableString] replaceOccurrencesOfString:@"\t◦\t" withString:@"  ◦ " options:0 range: htmlStringRange];
  257. [[htmlAttributedString mutableString] replaceOccurrencesOfString:@"\t▪\t" withString:@" ▪ " options:0 range: htmlStringRange];
  258. [htmlAttributedString removeAttribute:@"CTForegroundColorFromContext" range:htmlStringRange];
  259. [htmlAttributedString enumerateAttributesInRange:htmlStringRange options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:^(NSDictionary *attributes, NSRange range, BOOL *stop) {
  260. for (NSString *key in attributes) {
  261. if ([(UIColor *) attributes[key] isKindOfClass:[UIColor class]]) {
  262. UIColor *attrColor = (UIColor *) attributes[key];
  263. if ([[attrColor hexString] isEqualToString:@"#0000FF"]) {
  264. UIFont *tempFont = [UIFont fontWithName:@"Courier" size:font.pointSize];
  265. [htmlAttributedString setAttributes:@{NSForegroundColorAttributeName: accentColor, NSBackgroundColorAttributeName: [%c(ColorUtil) backgroundColorForTheme:themeName], NSFontAttributeName: (tempFont ? tempFont : font)} range:range];
  266. } else if ([[attrColor hexString] isEqualToString:@"#008000"]) {
  267. [htmlAttributedString setAttributes:@{NSForegroundColorAttributeName: fontColor, NSFontAttributeName:font} range:range];
  268. }
  269. } else if ([(NSURL *) attributes[key] isKindOfClass:[NSURL class]]) {
  270. NSURL *attrUrl = (NSURL *)attributes[key];
  271. if (([userDefaults objectForKey:@"ENLARGE_LINKS"] == nil) ? YES : [userDefaults boolForKey:@"ENLARGE_LINKS"]) {
  272. [htmlAttributedString addAttribute:NSFontAttributeName value:[%c(FontGenerator) boldFontOfSize:18 submission:NO willOffset:YES] range:range];
  273. }
  274. [htmlAttributedString addAttribute:NSForegroundColorAttributeName value:accentColor range:range];
  275. [htmlAttributedString addAttribute:NSUnderlineColorAttributeName value:[UIColor clearColor] range:range];
  276. //skipping showLinkContentType b/c not necessary and spoilers b/c MMMarkdown doesn't support them
  277. [htmlAttributedString yy_setTextHighlightRange:range color: accentColor backgroundColor:nil userInfo:@{@"url": attrUrl}];
  278. break;
  279. }
  280. }
  281. }];
  282. [htmlAttributedString beginEditing];
  283. [htmlAttributedString enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, [htmlAttributedString length]) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
  284. UIFont *attrFont = (UIFont *)value;
  285. BOOL isBold = (attrFont.fontDescriptor.symbolicTraits & UIFontDescriptorTraitBold) != 0;
  286. BOOL isItalic = (attrFont.fontDescriptor.symbolicTraits & UIFontDescriptorTraitItalic) != 0;
  287. UIFont *newFont = font;
  288. if (isBold){
  289. newFont = [%c(FontGenerator) boldFontOfSize:attrFont.pointSize submission:NO willOffset:NO];
  290. } else if (isItalic){
  291. newFont = [%c(FontGenerator) italicFontOfSize:attrFont.pointSize submission:NO willOffset:NO];
  292. }
  293. [htmlAttributedString removeAttribute:NSFontAttributeName range:range];
  294. [htmlAttributedString addAttribute:NSFontAttributeName value:newFont range:range];
  295. }];
  296. [htmlAttributedString endEditing];
  297. NSMutableAttributedString *newCommentText = [MSHookIvar<NSMutableAttributedString *>(self, "cellContent") initWithAttributedString:htmlAttributedString];
  298. NSAttributedString *tempAttributedString = [[NSAttributedString alloc] initWithString:@""];
  299. [newCommentText appendAttributedString:tempAttributedString]; //to keep the compiler happy
  300. [comment setAuthor:author];
  301. [comment setBody:body];
  302. id controller = MSHookIvar<id>(self, "parent");
  303. [self showMenu:nil];
  304. [MSHookIvar<id>(controller, "tableView") reloadData];
  305. [data[@"sender"] setEnabled:YES];
  306. }
  307. %end
  308. %hook RSubmission
  309. - (id)author {
  310. if (shouldSlideOverridePostInfo){
  311. return slidePostOverrideAuthor;
  312. } else {
  313. return %orig;
  314. }
  315. }
  316. - (id)htmlBody {
  317. if (shouldSlideOverridePostInfo){
  318. return slidePostOverrideBodyHtml;
  319. }
  320. else {
  321. return %orig;
  322. }
  323. }
  324. %end
  325. %hook CommentViewController
  326. %property(strong, nonatomic) UIButton *undeleteButton;
  327. - (void)viewDidLoad {
  328. %orig;
  329. shouldSlideOverridePostInfo = NO;
  330. slidePostOverrideAuthor = nil;
  331. slidePostOverrideBodyHtml = nil;
  332. UIButton *undeleteButton = createUndeleteButton();
  333. [undeleteButton setImage:[[undeleteButton currentImage] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
  334. [undeleteButton addTarget:self action:@selector(handleUndeletePost:) forControlEvents:UIControlEventTouchUpInside];
  335. [self setUndeleteButton:undeleteButton];
  336. }
  337. - (void)viewDidLayoutSubviews {
  338. %orig;
  339. if ([self undeleteButton]) {
  340. if ([self shouldAddUndeleteButtonToToolbar]) {
  341. [self addUndeleteButtonToToolbar];
  342. }
  343. }
  344. }
  345. - (void)loadAll:(id)arg1 {
  346. %orig;
  347. if ([self undeleteButton]){
  348. if ([self shouldAddUndeleteButtonToToolbar]){
  349. [self addUndeleteButtonToToolbar];
  350. }
  351. }
  352. }
  353. %new
  354. - (BOOL)shouldAddUndeleteButtonToToolbar {
  355. id post = MSHookIvar<id>(self, "submission");
  356. if ([post isSelf]) {
  357. NSString *author = [post author];
  358. if ([%c(TFHelper) shouldShowUndeleteButtonWithInfo:author isDeletedOnly:isTFDeletedOnly]) {
  359. return YES;
  360. }
  361. }
  362. return NO;
  363. }
  364. %new
  365. - (void)addUndeleteButtonToToolbar {
  366. UIToolbar *toolbar = [[self navigationController] toolbar];
  367. NSMutableArray *toolbarItems = [[toolbar items] mutableCopy];
  368. UIView *firstView = [toolbarItems[0] customView];
  369. if (firstView) {
  370. UIColor *tintColor = [toolbar tintColor];
  371. UIButton *undeleteButton = [self undeleteButton];
  372. [undeleteButton setTintColor:tintColor];
  373. if ([firstView isMemberOfClass:[UIView class]]) {
  374. if (![undeleteButton isDescendantOfView:firstView]){
  375. [firstView addSubview:undeleteButton];
  376. [undeleteButton setFrame:firstView.bounds];
  377. }
  378. } else if ([firstView isMemberOfClass:[UIButton class]] && undeleteButton != firstView) {
  379. UIBarButtonItem *undeleteItem = [[UIBarButtonItem alloc] initWithCustomView:undeleteButton];
  380. [toolbarItems insertObject:toolbarItems[1] atIndex:0];
  381. [toolbarItems insertObject:undeleteItem atIndex:0];
  382. [toolbar setItems:toolbarItems animated:NO];
  383. }
  384. }
  385. }
  386. %new
  387. - (void)handleUndeletePost:(id)sender {
  388. shouldSlideOverridePostInfo = YES;
  389. [sender setEnabled:NO];
  390. [%c(TFHelper) getUndeleteDataWithID:[MSHookIvar<id>(self, "submission") name] isComment:NO timeout:pushshiftRequestTimeoutValue extraData:@{@"sender" : sender} completionTarget:self completionSelector:@selector(completeUndeletePostAction:)];
  391. }
  392. %new
  393. - (void)completeUndeletePostAction:(NSDictionary *)data {
  394. slidePostOverrideAuthor = data[@"author"];
  395. slidePostOverrideBodyHtml = [%c(MMMarkdown) HTMLStringWithMarkdown:data[@"body"] extensions:MMMarkdownExtensionsGitHubFlavored error:nil];
  396. [self refresh:nil];
  397. [data[@"sender"] setEnabled:YES];
  398. }
  399. %end
  400. %end
  401. static void loadPrefs(){
  402. NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/User/Library/Preferences/com.lint.undelete.prefs.plist"];
  403. if (prefs){
  404. isEnabled = [prefs objectForKey:@"isEnabled"] ? [[prefs objectForKey:@"isEnabled"] boolValue] : YES;
  405. isSlideEnabled = [prefs objectForKey:@"isSlideEnabled"] ? [[prefs objectForKey:@"isSlideEnabled"] boolValue] : YES;
  406. isTFDeletedOnly = [prefs objectForKey:@"isTFDeletedOnly"] ? [[prefs objectForKey:@"isTFDeletedOnly"] boolValue] : YES;
  407. pushshiftRequestTimeoutValue = [prefs objectForKey:@"requestTimeoutValue"] ? [[prefs objectForKey:@"requestTimeoutValue"] doubleValue] : 10;
  408. } else {
  409. isEnabled = YES;
  410. isSlideEnabled = YES;
  411. isTFDeletedOnly = YES;
  412. pushshiftRequestTimeoutValue = 10;
  413. }
  414. }
  415. static void prefsChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
  416. loadPrefs();
  417. }
  418. %ctor {
  419. loadPrefs();
  420. NSString* processName = [[NSProcessInfo processInfo] processName];
  421. if ([processName isEqualToString:@"Slide for Reddit"]){
  422. if (isSlideEnabled && isEnabled){
  423. CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)prefsChanged, CFSTR("com.lint.undelete.prefs.changed"), NULL, CFNotificationSuspensionBehaviorCoalesce);
  424. %init(Slide, CommentDepthCell = objc_getClass("Slide_for_Reddit.CommentDepthCell"), RSubmission = objc_getClass("Slide_for_Reddit.RSubmission"), CommentViewController = objc_getClass("Slide_for_Reddit.CommentViewController"));
  425. }
  426. }
  427. }