T1Model.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. //
  2. // T1Model.m
  3. // YYKitExample
  4. //
  5. // Created by ibireme on 15/10/9.
  6. // Copyright (C) 2015 ibireme. All rights reserved.
  7. //
  8. #import "T1Model.h"
  9. @implementation T1UserMention
  10. + (NSDictionary *)modelCustomPropertyMapper {
  11. return @{
  12. @"screenName" : @"screen_name",
  13. @"uidStr" : @"id_str",
  14. @"uid" : @"id",
  15. };
  16. }
  17. + (NSDictionary *)modelContainerPropertyGenericClass {
  18. return @{ @"indices" : [NSNumber class] };
  19. }
  20. - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
  21. int rangeCount = (int)_indices.count / 2;
  22. NSMutableArray *ranges = nil;
  23. for (int i = 0; i < rangeCount; i++) {
  24. int from = ((NSNumber *)_indices[i * 2]).intValue;
  25. int to = ((NSNumber *)_indices[i * 2 + 1]).intValue;
  26. NSRange range = NSMakeRange(from, to >= from ? (to - from) : 0);
  27. if (i == 0) {
  28. _range = range;
  29. }
  30. if (rangeCount > 1) {
  31. [ranges addObject:[NSValue valueWithRange:range]];
  32. }
  33. }
  34. _ranges = ranges;
  35. return YES;
  36. }
  37. @end
  38. @implementation T1URL
  39. + (NSDictionary *)modelCustomPropertyMapper {
  40. return @{ @"screenName" : @"screen_name",
  41. @"idStr" : @"id_str",
  42. @"displayURL" : @"display_url",
  43. @"expandedURL" : @"expanded_url"};
  44. }
  45. + (NSDictionary *)modelContainerPropertyGenericClass {
  46. return @{ @"indices" : [NSNumber class] };
  47. }
  48. - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
  49. int rangeCount = (int)_indices.count / 2;
  50. NSMutableArray *ranges = nil;
  51. for (int i = 0; i < rangeCount; i++) {
  52. int from = ((NSNumber *)_indices[i * 2]).intValue;
  53. int to = ((NSNumber *)_indices[i * 2 + 1]).intValue;
  54. NSRange range = NSMakeRange(from, to >= from ? (to - from) : 0);
  55. if (i == 0) {
  56. _range = range;
  57. }
  58. if (rangeCount > 1) {
  59. [ranges addObject:[NSValue valueWithRange:range]];
  60. }
  61. }
  62. _ranges = ranges;
  63. return YES;
  64. }
  65. @end
  66. @implementation T1HashTag
  67. + (NSDictionary *)modelContainerPropertyGenericClass {
  68. return @{ @"indices" : [NSNumber class] };
  69. }
  70. - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
  71. int rangeCount = (int)_indices.count / 2;
  72. NSMutableArray *ranges = nil;
  73. for (int i = 0; i < rangeCount; i++) {
  74. int from = ((NSNumber *)_indices[i * 2]).intValue;
  75. int to = ((NSNumber *)_indices[i * 2 + 1]).intValue;
  76. NSRange range = NSMakeRange(from, to >= from ? (to - from) : 0);
  77. if (i == 0) {
  78. _range = range;
  79. }
  80. if (rangeCount > 1) {
  81. [ranges addObject:[NSValue valueWithRange:range]];
  82. }
  83. }
  84. _ranges = ranges;
  85. return YES;
  86. }
  87. @end
  88. @implementation T1MediaMeta
  89. + (NSDictionary *)modelContainerPropertyGenericClass {
  90. return @{ @"faces" : [NSValue class] };
  91. }
  92. - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
  93. _size = CGSizeMake(_width, _height);
  94. _isCrop = [_resize isEqualToString:@"crop"];
  95. _faces = nil;
  96. NSArray *faceDics = dic[@"faces"];
  97. if ([faceDics isKindOfClass:[NSArray class]] && faceDics.count > 0) {
  98. NSMutableArray *faces = [NSMutableArray new];
  99. for (NSDictionary *faceDic in faceDics) {
  100. if ([faceDic isKindOfClass:[NSDictionary class]]) {
  101. int x = [faceDic intValueForKey:@"x" default:0];
  102. int y = [faceDic intValueForKey:@"y" default:0];
  103. int w = [faceDic intValueForKey:@"w" default:0];
  104. int h = [faceDic intValueForKey:@"h" default:0];
  105. [faces addObject:[NSValue valueWithCGRect:CGRectMake(x, y, w, h)]];
  106. }
  107. }
  108. _faces = faces;
  109. }
  110. return YES;
  111. }
  112. @end
  113. @implementation T1Media
  114. + (NSDictionary *)modelCustomPropertyMapper {
  115. return @{
  116. @"idStr" : @"id_str",
  117. @"mediaURLHttps" : @"media_url_https",
  118. @"mediaURL" : @"media_url",
  119. @"expandedURL" : @"expanded_url",
  120. @"displayURL" : @"display_url",
  121. @"mid" : @"id",
  122. @"midStr" : @"id_str",
  123. @"mediaThumb" : @"sizes.thumb",
  124. @"mediaSmall" : @"sizes.small",
  125. @"mediaMedium" : @"sizes.medium",
  126. @"mediaLarge" : @"sizes.large",
  127. @"mediaOrig" : @"sizes.orig"
  128. };
  129. }
  130. - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
  131. int rangeCount = (int)_indices.count / 2;
  132. NSMutableArray *ranges = nil;
  133. for (int i = 0; i < rangeCount; i++) {
  134. int from = ((NSNumber *)_indices[i * 2]).intValue;
  135. int to = ((NSNumber *)_indices[i * 2 + 1]).intValue;
  136. NSRange range = NSMakeRange(from, to >= from ? (to - from) : 0);
  137. if (i == 0) {
  138. _range = range;
  139. }
  140. if (rangeCount > 1) {
  141. [ranges addObject:[NSValue valueWithRange:range]];
  142. }
  143. }
  144. _ranges = ranges;
  145. NSDictionary *featureDics = dic[@"features"];
  146. if ([featureDics isKindOfClass:[NSDictionary class]]) {
  147. [_mediaThumb modelSetWithDictionary:featureDics[@"thumb"]];
  148. [_mediaSmall modelSetWithDictionary:featureDics[@"small"]];
  149. [_mediaMedium modelSetWithDictionary:featureDics[@"medium"]];
  150. [_mediaLarge modelSetWithDictionary:featureDics[@"large"]];
  151. [_mediaOrig modelSetWithDictionary:featureDics[@"orig"]];
  152. NSString *url;
  153. url = [_mediaURL stringByAppendingString:@":thumb"];
  154. _mediaThumb.url = url ? [NSURL URLWithString:url] : nil;
  155. url = [_mediaURL stringByAppendingString:@":small"];
  156. _mediaSmall.url = url ? [NSURL URLWithString:url] : nil;
  157. url = [_mediaURL stringByAppendingString:@":medium"];
  158. _mediaMedium.url = url ? [NSURL URLWithString:url] : nil;
  159. url = [_mediaURL stringByAppendingString:@":large"];
  160. _mediaLarge.url = url ? [NSURL URLWithString:url] : nil;
  161. url = [_mediaURL stringByAppendingString:@":orig"];
  162. _mediaOrig.url = url ? [NSURL URLWithString:url] : nil;
  163. }
  164. return YES;
  165. }
  166. @end
  167. @implementation T1Place
  168. + (NSDictionary *)modelCustomPropertyMapper {
  169. return @{
  170. @"fullName" : @"full_name",
  171. @"placeType" : @"place_type",
  172. @"countryCode" : @"country_code",
  173. @"pid" : @"id",
  174. @"boundingBox" : @"bounding_box",
  175. @"containedWithin" : @"contained_within"
  176. };
  177. }
  178. @end
  179. @implementation T1Card
  180. + (NSDictionary *)modelContainerPropertyGenericClass {
  181. return @{ @"users" : [T1User class] };
  182. }
  183. + (NSDictionary *)modelCustomPropertyMapper {
  184. return @{ @"cardTypeURL" : @"card_type_url", @"bindingValues" : @"binding_values" };
  185. }
  186. @end
  187. @implementation T1User
  188. + (NSDictionary *)modelCustomPropertyMapper {
  189. return @{
  190. @"isProtected" : @"protected",
  191. @"isTranslator" : @"is_translator",
  192. @"profileImageURL" : @"profile_image_url",
  193. @"createdAt" : @"created_at",
  194. @"uid" : @"id",
  195. @"defaultProfileImage" : @"default_profile_image",
  196. @"listedCount" : @"listed_count",
  197. @"profileBackgroundColor" : @"profile_background_color",
  198. @"followRequestSent" : @"follow_request_sent",
  199. @"desc" : @"description",
  200. @"geoEnabled" : @"geo_enabled",
  201. @"profileTextColor" : @"profile_text_color",
  202. @"statusesCount" : @"statuses_count",
  203. @"profileBackgroundTile" : @"profile_background_tile",
  204. @"profileUseBackgroundImage" : @"profile_use_background_image",
  205. @"uidStr" : @"id_str",
  206. @"profileImageURLHttps" : @"profile_image_url_https",
  207. @"profileSidebarFillColor" : @"profile_sidebar_fill_color",
  208. @"profileSidebarBorderColor" : @"profile_sidebar_border_color",
  209. @"contributorsEnabled" : @"contributors_enabled",
  210. @"defaultProfile" : @"default_profile",
  211. @"screenName" : @"screen_name",
  212. @"timeZone" : @"time_zone",
  213. @"profileBackgroundImageURL" : @"profile_background_image_url",
  214. @"profileBackgroundImageURLHttps" : @"profile_background_image_url_https",
  215. @"profileLinkColor" : @"profile_link_color",
  216. @"favouritesCount" : @"favourites_count",
  217. @"isTranslationEnabled" : @"is_translation_enabled",
  218. @"utcOffset" : @"utc_offset",
  219. @"friendsCount" : @"friends_count",
  220. @"hasExtendedProfile" : @"has_extended_profile"
  221. };
  222. }
  223. - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
  224. if (_profileImageURL) {
  225. NSMutableString *url = _profileImageURL.absoluteString.mutableCopy;
  226. NSString *ext = [url pathExtension];
  227. if (ext.length && url.length > ext.length + 2 + 7) {
  228. NSRange range = NSMakeRange(url.length - ext.length - 1 - 7, 7);
  229. if ([[url substringWithRange:range] isEqualToString:@"_normal"]) {
  230. [url replaceCharactersInRange:range withString:@"_reasonably_small"];
  231. _profileImageURLReasonablySmall = [NSURL URLWithString:url];
  232. }
  233. }
  234. }
  235. return YES;
  236. }
  237. @end
  238. @implementation T1Tweet
  239. + (NSDictionary *)modelContainerPropertyGenericClass {
  240. return @{
  241. @"medias" : [T1Media class],
  242. @"extendedMedias" : [T1Media class],
  243. @"userMentions" : [T1UserMention class],
  244. @"urls" : [T1URL class],
  245. @"hashTags" : [T1HashTag class]
  246. };
  247. }
  248. + (NSDictionary *)modelCustomPropertyMapper {
  249. return @{
  250. @"isQuoteStatus" : @"is_quote_status",
  251. @"favoriteCount" : @"favorite_count",
  252. @"conversationID" : @"conversation_id",
  253. @"inReplyToScreenName" : @"in_reply_to_screen_name",
  254. @"retweetCount" : @"retweet_count",
  255. @"tid" : @"id",
  256. @"inReplyToUserId" : @"in_reply_to_user_id",
  257. @"supplementalLanguage" : @"supplemental_language",
  258. @"createdAt" : @"created_at",
  259. @"inReplyToStatusIDStr" : @"in_reply_to_status_id_str",
  260. @"inReplyToStatusID" : @"in_reply_to_status_id",
  261. @"inReplyToUserIDStr" : @"in_reply_to_user_id_str",
  262. @"tidStr" : @"id_str",
  263. @"retweetedStatus" : @"retweeted_status",
  264. @"quotedStatus" : @"quoted_status",
  265. @"medias" : @"emtities.media",
  266. @"extendedMedias" : @"extended_entities.media",
  267. @"userMentions" : @"entities.userMentions",
  268. @"urls" : @"entities.urls",
  269. @"hashTags" : @"entities.hashtags"
  270. };
  271. }
  272. @end
  273. @implementation T1Conversation
  274. + (NSDictionary *)modelContainerPropertyGenericClass {
  275. return @{
  276. @"participantIDs" : [NSString class],
  277. @"contextIDs" : [NSString class],
  278. };
  279. }
  280. + (NSDictionary *)modelCustomPropertyMapper {
  281. return @{
  282. @"targetTweetID" : @"context.target_tweet_id",
  283. @"participantIDs" : @"context.participant_ids",
  284. @"participantsCount" : @"context.participants_count",
  285. @"targetCount" : @"context.target_count",
  286. @"rootUserID" : @"ccontext.root_user_id",
  287. @"contextIDs" : @"ids"
  288. };
  289. }
  290. @end
  291. @implementation T1APIRespose
  292. + (NSDictionary *)modelContainerPropertyGenericClass {
  293. return @{
  294. @"users" : [T1User class],
  295. @"tweets" : [T1Tweet class],
  296. @"timeline" : [NSDictionary class],
  297. @"hashTags" : [T1HashTag class]
  298. };
  299. }
  300. + (NSDictionary *)modelCustomPropertyMapper {
  301. return @{
  302. @"users" : @"twitter_objects.users",
  303. @"tweets" : @"twitter_objects.tweets",
  304. @"timeline" : @"response.timeline",
  305. @"cursorTop" : @"response.cursor.top",
  306. @"cursorBottom" : @"response.cursor.bottom",
  307. @"cursorGaps" : @"response.cursor.gaps"
  308. };
  309. }
  310. - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
  311. NSMutableArray *timelineItems = [NSMutableArray new];
  312. for (NSDictionary *dic in _timeline) {
  313. NSDictionary *tDic = dic[@"tweet"];
  314. if ([tDic isKindOfClass:[NSDictionary class]]) {
  315. NSString *tid = tDic[@"id"];
  316. if ([tid isKindOfClass:[NSString class]]) {
  317. T1Tweet *tweet = _tweets[tid];
  318. if (tweet) [timelineItems addObject:tweet];
  319. }
  320. } else {
  321. NSDictionary *cDic = dic[@"conversation"];
  322. if ([cDic isKindOfClass:[NSDictionary class]]) {
  323. T1Conversation *conversation = [T1Conversation modelWithDictionary:cDic];
  324. NSDictionary *entityID = dic[@"entity_id"];
  325. if ([entityID isKindOfClass:[NSDictionary class]]) {
  326. NSArray *ids = entityID[@"ids"];
  327. if ([ids isKindOfClass:[NSArray class]]) {
  328. conversation.entityIDs = ids;
  329. }
  330. }
  331. NSMutableArray *tweets = [NSMutableArray new];
  332. for (NSString *tid in conversation.contextIDs) {
  333. T1Tweet *tweet = _tweets[tid];
  334. if (tweet) [tweets addObject:tweet];
  335. }
  336. if (tweets.count > 1) {
  337. conversation.tweets = tweets;
  338. [timelineItems addObject:conversation];
  339. }
  340. }
  341. }
  342. }
  343. _timelineItmes = timelineItems;
  344. for (id item in _timelineItmes) {
  345. if ([item isKindOfClass:[T1Tweet class]]) {
  346. [self _updateTweetReference:item];
  347. } else if ([item isKindOfClass:[T1Conversation class]]) {
  348. for (T1Tweet *tweet in ((T1Conversation *)item).tweets) {
  349. [self _updateTweetReference:tweet];
  350. }
  351. }
  352. }
  353. return YES;
  354. }
  355. - (void)_updateTweetReference:(T1Tweet *)tweet {
  356. if (!tweet) return;
  357. T1User *user;
  358. for (T1UserMention *mention in tweet.userMentions) {
  359. user = mention.uidStr ? _users[mention.uidStr] : nil;
  360. mention.user = user;
  361. }
  362. for (T1UserMention *mention in tweet.retweetedStatus.userMentions) {
  363. user = mention.uidStr ? _users[mention.uidStr] : nil;
  364. mention.user = user;
  365. }
  366. user = tweet.user;
  367. user = user.uidStr ? _users[user.uidStr] : nil;
  368. tweet.user = user;
  369. user = tweet.retweetedStatus.user;
  370. user = user.uidStr ? _users[user.uidStr] : nil;
  371. tweet.retweetedStatus.user = user;
  372. user = tweet.quotedStatus.user;
  373. user = user.uidStr ? _users[user.uidStr] : nil;
  374. tweet.quotedStatus.user = user;
  375. }
  376. @end