TNLExample/TNLXImageTableViewController.m (180 lines of code) (raw):

// // TNLXFirstViewController.m // TNLExample // // Created on 7/24/14. // Copyright © 2020 Twitter. All rights reserved. // #import <objc/runtime.h> #import <TwitterNetworkLayer/TwitterNetworkLayer.h> #import "TAPI.h" #import "TNLXImageSupport.h" #import "TNLXImageTableViewController.h" #import "TNLXImageViewController.h" @import UIKit; #define REDUNDANCY_COUNT (0) #define COUNT (50) @interface TNLXImageTableViewController () <UITableViewDataSource, UITableViewDelegate, TNLRequestDelegate> { IBOutlet UIProgressView *_initialLoadProgressView; IBOutlet UITableView *_tableView; TNLRequestOperation *_initialOp; NSArray<id<TAPIImageEntityModel>> *_results; } @end @interface TNLXImageCell : UITableViewCell @property (nonatomic, readonly) TNLXImageView *smartImageView; @end @implementation TNLXImageTableViewController - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; NSLog(@"%@", NSStringFromSelector(_cmd)); } - (void)viewDidLoad { [super viewDidLoad]; [_tableView registerClass:[TNLXImageCell class] forCellReuseIdentifier:@"ImageCell"]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self _startInitialLoadIfNeeded]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [self _cleanupInitialLoadIfNotFinished]; } - (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleDefault; } #pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { TNLXImageCell *cell = (id)[tableView cellForRowAtIndexPath:indexPath]; id<TAPIImageEntityModel> info = cell.smartImageView.imageEntity; TNLXImageViewController *vc = [[TNLXImageViewController alloc] initWithImageEntity:info]; vc.lowResImage = cell.smartImageView.image; vc.blockingOperation = cell.smartImageView.imageLoadOperation; vc.modalPresentationStyle = UIModalPresentationFullScreen; vc.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStyleDone target:self action:@selector(dismissImageViewController)]; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; [cell.smartImageView addObserver:self forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:NULL]; [self presentViewController:nav animated:YES completion:NULL]; } - (void)dismissImageViewController { TNLXImageCell *cell = (id)[_tableView cellForRowAtIndexPath:_tableView.indexPathForSelectedRow]; [cell.smartImageView removeObserver:self forKeyPath:@"image"]; [_tableView deselectRowAtIndexPath:_tableView.indexPathForSelectedRow animated:YES]; [self dismissViewControllerAnimated:YES completion:NULL]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { UINavigationController *nav = (id)self.presentedViewController; TNLXImageViewController *vc = (id)nav.viewControllers[0]; [vc setLowResImage:[(TNLXImageView *)object image]]; } #pragma mark - UITableViewDataSource - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TNLXImageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ImageCell" forIndexPath:indexPath]; cell.contentView.frame = cell.bounds; assert(cell != nil); cell.smartImageView.imageEntity = _results[(NSUInteger)indexPath.row]; return cell; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return (NSInteger)_results.count; } #pragma mark - TNL - (void)tnl_requestOperation:(TNLRequestOperation *)op didCompleteWithResponse:(TAPISearchResponse *)response { assert([NSThread isMainThread]); if (!_initialOp) { return; } _initialOp = nil; NSArray *results = [response imagesFromStatuesRemovingSensitiveImages:YES]; _results = _results ? [_results arrayByAddingObjectsFromArray:results] : results; if (_results.count < COUNT && response.nextResultsObject) { [_initialLoadProgressView setProgress:(float)((double)_results.count / (double)COUNT) animated:YES]; [self _continueLoading:response.nextResultsObject]; return; } [_initialLoadProgressView setProgress:1.0 animated:YES]; _initialLoadProgressView.hidden = YES; _tableView.hidden = NO; [_tableView reloadData]; } - (void)tnl_requestOperation:(TNLRequestOperation *)op hydrateRequest:(TAPIRequest *)request completion:(TNLRequestHydrateCompletionBlock)complete { [[TAPIClient sharedInstance] tnl_requestOperation:op hydrateRequest:request completion:complete]; } - (void)tnl_requestOperation:(TNLRequestOperation *)op authorizeURLRequest:(NSURLRequest *)URLRequest completion:(TNLAuthorizeCompletionBlock)completion { [[TAPIClient sharedInstance] tnl_requestOperation:op authorizeURLRequest:URLRequest completion:completion]; } #pragma mark - Private - (void)_startInitialLoadIfNeeded { if (!_initialOp && !_results) { _initialLoadProgressView.progress = 0; _initialLoadProgressView.hidden = NO; _tableView.hidden = YES; TAPISearchRequest *request = [[TAPISearchRequest alloc] initWithQuery:@"Star Wars"]; // TODO request.redundancyCount = REDUNDANCY_COUNT; _initialOp = [[TAPIClient sharedInstance] startRequest:request delegate:self]; } } - (void)_continueLoading:(id)nextResultsObject { assert(!_initialOp); if (!_initialOp) { TAPISearchRequest *request = [[TAPISearchRequest alloc] initWithNextResultsObject:nextResultsObject]; // TODO request.redundancyCount = REDUNDANCY_COUNT; _initialOp = [[TAPIClient sharedInstance] startRequest:request delegate:self]; } } - (void)_cleanupInitialLoadIfNotFinished { if (_initialOp) { [_initialOp cancelWithSource:NSStringFromSelector(_cmd)]; _initialOp = nil; _initialLoadProgressView.progress = 0; } } @end @implementation TNLXImageCell - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { _smartImageView = [[TNLXImageView alloc] initWithFrame:self.contentView.bounds]; _smartImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; _smartImageView.contentMode = UIViewContentModeScaleAspectFit; [self.contentView addSubview:_smartImageView]; self.separatorInset = UIEdgeInsetsZero; } return self; } - (void)prepareForReuse { [super prepareForReuse]; _smartImageView.image = nil; } @end