Files
transshift/TransmissionRPCClient/PeerListController.m
2015-08-11 17:58:10 +03:00

303 lines
9.2 KiB
Objective-C

//
// PeerListController.m
// TransmissionRPCClient
//
// Created by Alexey Chechetkin on 30.06.15.
// Copyright (c) 2015 Alexey Chechetkin. All rights reserved.
//
#import "PeerListController.h"
#import "PeerListCell.h"
#import "PeerStatCell.h"
#import "FlagDescriptionView.h"
#import "IPGeoInfoController.h"
#import "NSObject+DataObject.h"
#import "GlobalConsts.h"
#import "GeoIpConnector.h"
#define ROWHIGHT_PEERINFOHEADER 44
#define ROWHIGHT_PEERINFO 30
#define ROWHIGHT_PEERSTAT 114
#define SECTIONFOOTER_HEIGHT 237
@implementation PeerListController
{
NSArray *_sectionTitles;
UIPopoverController *_popOver;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_sectionTitles = @[ NSLocalizedString(@"Peers", @""), NSLocalizedString(@"Peers stats", @"") ];
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
self.refreshControl = refreshControl;
[refreshControl addTarget:self action:@selector(askDelegateToUpdateData) forControlEvents:UIControlEventValueChanged];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.navigationItem.leftBarButtonItem.title = NSLocalizedString(@"Info", @"");
}
- (void)askDelegateToUpdateData
{
//[self.refreshControl endRefreshing];
if( _delegate && [_delegate respondsToSelector:@selector(peerListNeedUpdatePeersForTorrentId:)])
[_delegate peerListNeedUpdatePeersForTorrentId:_torrentId];
}
- (void)setPeers:(NSArray *)peers
{
//_peers = peers;
[self.refreshControl endRefreshing];
// this is the first data - add section
if( peers.count > 0 && _peers.count == 0 )
{
_peers = peers;
[self.tableView beginUpdates];
[self.tableView insertSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
return;
}
// there is no data - clear section
if( _peers.count > 0 && peers.count == 0 )
{
_peers = peers;
[self.tableView beginUpdates];
[self.tableView deleteSections: [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,2)] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
return;
}
NSUInteger count = MAX(_peers.count,peers.count);
NSMutableArray *indexPathsToAdd = [NSMutableArray array];
NSMutableArray *indexPathsToRemove = [NSMutableArray array];
NSMutableArray *indexPathsToReload = [NSMutableArray array];
BOOL needToUpdate = NO;
for (NSUInteger i = 0; i < count; i++)
{
NSIndexPath *path = [NSIndexPath indexPathForRow:(i + 1) inSection:0];
TRPeerInfo *cur = i < _peers.count ? _peers[i] : nil;
TRPeerInfo *new = i < peers.count ? peers[i] : nil;
// there is no current element
// this index is new and should be re
if( !cur )
{
[indexPathsToAdd addObject:path];
needToUpdate = YES;
}
// there is no element in new data
// this index is stale and should be removed
else if( !new )
{
[indexPathsToRemove addObject:path];
needToUpdate = YES;
}
else
{
// compare data
if( [cur.ipAddress isEqualToString: new.ipAddress] )
{
// update cell
PeerListCell *cell = (PeerListCell*)[self.tableView cellForRowAtIndexPath:path];
if( cell )
[self updatePeerListCell:cell withInfo:cur];
}
// diffrent data, reload data in cell
else
{
[indexPathsToReload addObject:path];
needToUpdate = YES;
}
}
}
_peers = peers;
if( needToUpdate )
{
[self.tableView beginUpdates];
if( indexPathsToAdd.count > 0 )
[self.tableView insertRowsAtIndexPaths:indexPathsToAdd withRowAnimation:UITableViewRowAnimationAutomatic];
if( indexPathsToRemove.count > 0 )
[self.tableView deleteRowsAtIndexPaths:indexPathsToRemove withRowAnimation:UITableViewRowAnimationAutomatic];
if( indexPathsToReload.count > 0 )
[self.tableView reloadRowsAtIndexPaths:indexPathsToReload withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
}
PeerStatCell *cell = (PeerStatCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
if( cell )
[self updatePeerStatCell:cell witInfo:_peerStat];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
self.infoMessage = _peers.count > 0 ? nil : NSLocalizedString(@"There are no peers avalable.", @"");
return _peers.count > 0 ? _sectionTitles.count : 0;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return _sectionTitles[section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section + 1 for header row
if( section == 0 )
return _peers.count + 1;
// second section (PeerStats) has only one row
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if( indexPath.section == 1 )
return ROWHIGHT_PEERSTAT;
if( indexPath.row == 0 )
return ROWHIGHT_PEERINFOHEADER;
return ROWHIGHT_PEERINFO;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
static UIView *flagsDescriptionView = nil;
if( section == 0 )
{
if( !flagsDescriptionView )
flagsDescriptionView = [FlagDescriptionView flagDescriptionView];
return flagsDescriptionView;
}
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
if( section == 0 )
return SECTIONFOOTER_HEIGHT;
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// header row
if( indexPath.section == 0 && indexPath.row == 0 )
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CELL_ID_PEERLISTHEADERCELL forIndexPath:indexPath];
return cell;
}
// peer info
if( indexPath.section == 0 )
{
PeerListCell *cell = [tableView dequeueReusableCellWithIdentifier:CELL_ID_PEERLISTCELL forIndexPath:indexPath];
TRPeerInfo *info = self.peers[indexPath.row - 1];
[self updatePeerListCell:cell withInfo:info];
return cell;
}
// peer stat section
if( indexPath.section == 1 )
{
PeerStatCell *cell = [tableView dequeueReusableCellWithIdentifier:CELL_ID_PEERSTAT forIndexPath:indexPath];
[self updatePeerStatCell:cell witInfo:_peerStat];
return cell;
}
return nil;
}
- (void)updatePeerStatCell:(PeerStatCell *)cell witInfo:(TRPeerStat *)info
{
cell.labelFromCache.text = info.fromChache;
cell.labelFromDht.text = info.fromDht;
cell.labelFromLpd.text = info.fromLpd;
cell.labelFromPex.text = info.fromPex;
cell.labelFromTracker.text = info.fromTracker;
cell.labelFromIncoming.text = info.fromIncoming;
}
- (void)updatePeerListCell:(PeerListCell *)cell withInfo:(TRPeerInfo*)info
{
cell.clientLabel.text = info.clientName;
cell.addressLabel.text = info.ipAddress;
cell.progressLabel.text = info.progressString;
cell.flagLabel.text = info.flagString;
cell.downloadLabel.text = info.rateToClient > 0 ? info.rateToClientString : @"-";
cell.uploadLabel.text = info.rateToPeer > 0 ? info.rateToPeerString : @"-";
cell.isSecure = info.isEncrypted;
cell.isUTPEnabled = info.isUTP;
if ( self.splitViewController )
{
cell.addressLabel.userInteractionEnabled = YES;
cell.addressLabel.textColor = self.tableView.tintColor;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showGeoIpController:)];
tap.dataObject = info;
info.dataObject = cell;
[cell.addressLabel addGestureRecognizer:tap];
}
}
- (void)showGeoIpController:(UIGestureRecognizer *)sender
{
if( _popOver )
{
[_popOver dismissPopoverAnimated:NO];
}
TRPeerInfo *info = sender.dataObject;
IPGeoInfoController *c = instantiateController( CONROLLER_ID_IPGEOINFO );
c.ipAddress = info.ipAddress;
c.title = [NSString stringWithFormat:@"IP %@:%i", info.ipAddress, info.port];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:c];
PeerListCell *cell = info.dataObject;
CGRect rect = cell.addressLabel.frame;
rect.size.width = 30;
_popOver = [[UIPopoverController alloc] initWithContentViewController:nav];
[_popOver presentPopoverFromRect:rect inView:cell permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
@end