VLCLocalServerListViewController.m 28.2 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * VLCLocalServerListViewController.m
 * VLC for iOS
 *****************************************************************************
5
 * Copyright (c) 2013-2015 VideoLAN. All rights reserved.
6 7 8 9 10 11 12 13
 * $Id$
 *
 * Authors: Felix Paul Kühne <fkuehne # videolan.org>
 *          Pierre SAGASPE <pierre.sagaspe # me.com>
 *          Gleb Pinigin <gpinigin # gmail.com>
 *
 * Refer to the COPYING file of the official project for license.
 *****************************************************************************/
14 15 16 17 18

#import "VLCLocalServerListViewController.h"
#import "VLCAppDelegate.h"
#import "UPnPManager.h"
#import "VLCLocalNetworkListCell.h"
19
#import "VLCLocalServerFolderListViewController.h"
20
#import "VLCLocalPlexFolderListViewController.h"
21
#import "VLCPlexConnectServerViewController.h"
22 23
#import "VLCSharedLibraryListViewController.h"
#import "VLCSharedLibraryParser.h"
24 25
#import <QuartzCore/QuartzCore.h>
#import "GHRevealViewController.h"
26
#import "VLCNetworkLoginViewController.h"
27
#import "VLCPlaylistViewController.h"
28
#import "VLCHTTPUploaderController.h"
29
#import "Reachability.h"
30
#import "VLCNavigationController.h"
31

32 33
#define kPlexServiceType @"_plexmediasvr._tcp."

34
@interface VLCLocalServerListViewController () <UITableViewDataSource, UITableViewDelegate, NSNetServiceBrowserDelegate, VLCNetworkLoginViewController, NSNetServiceDelegate, VLCMediaListDelegate, UPnPDBObserver>
35 36
{
    UIBarButtonItem *_backToMenuButton;
37 38
    NSArray *_sectionHeaderTexts;

39
    NSNetServiceBrowser *_ftpNetServiceBrowser;
40
    NSNetServiceBrowser *_PlexNetServiceBrowser;
41
    NSNetServiceBrowser *_httpNetServiceBrowser;
42 43
    NSMutableArray *_PlexServices;
    NSMutableArray *_PlexServicesInfo;
44 45
    NSMutableArray *_httpServices;
    NSMutableArray *_httpServicesInfo;
46
    NSMutableArray *_rawNetServices;
47 48
    NSMutableArray *_ftpServices;

49 50
    NSArray *_filteredUPNPDevices;
    NSArray *_UPNPdevices;
51

52 53
    VLCMediaDiscoverer *_sapDiscoverer;
    VLCMediaDiscoverer *_dsmDiscoverer;
54

55
    VLCNetworkLoginViewController *_loginViewController;
Pierre SAGASPE's avatar
Pierre SAGASPE committed
56

57 58
    VLCSharedLibraryParser *_httpParser;

59
    UIRefreshControl *_refreshControl;
60
    UIActivityIndicatorView *_activityIndicator;
61 62
    Reachability *_reachability;

63 64
    NSString *_myHostName;

65
    BOOL _udnpDiscoveryRunning;
66
    NSTimer *_searchTimer;
67 68
}

69 70
@property (nonatomic) VLCHTTPUploaderController *uploadController;

71 72 73 74
@end

@implementation VLCLocalServerListViewController

75 76
- (void)dealloc
{
77
    [[NSNotificationCenter defaultCenter] removeObserver:self];
78

79
    [_reachability stopNotifier];
80
    [_ftpNetServiceBrowser stop];
81
    [_PlexNetServiceBrowser stop];
82
    [_httpNetServiceBrowser stop];
83 84
}

85 86 87
- (void)loadView
{
    _tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
88
    _tableView.backgroundColor = [UIColor VLCDarkBackgroundColor];
89 90
    _tableView.delegate = self;
    _tableView.dataSource = self;
91
    _tableView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
92
    _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
93
    self.view = _tableView;
94 95 96 97 98
    _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    _activityIndicator.center = _tableView.center;
    _activityIndicator.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin;
    _activityIndicator.hidesWhenStopped = YES;
    [self.view addSubview:_activityIndicator];
99 100
}

101 102 103 104
- (void)applicationWillResignActive:(NSNotification *)notification
{
    [self _stopUPNPDiscovery];
    [self _stopSAPDiscovery];
105
    [self _stopDSMDiscovery];
106 107 108 109 110 111 112
}

- (void)applicationDidBecomeActive:(NSNotification *)notification
{
    if (_reachability.currentReachabilityStatus == ReachableViaWiFi) {
        [self performSelectorInBackground:@selector(_startUPNPDiscovery) withObject:nil];
        [self performSelectorInBackground:@selector(_startSAPDiscovery) withObject:nil];
113
        [self performSelectorInBackground:@selector(_startDSMDiscovery) withObject:nil];
114 115 116
    }
}

117 118 119 120
- (void)viewDidLoad
{
    [super viewDidLoad];

121 122 123 124 125 126
    NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];

    [defaultCenter addObserver:self
                      selector:@selector(applicationWillResignActive:)
                          name:UIApplicationWillResignActiveNotification
                        object:[UIApplication sharedApplication]];
127

128 129 130 131 132 133 134 135 136
    [defaultCenter addObserver:self
                      selector:@selector(applicationDidBecomeActive:)
                          name:UIApplicationDidBecomeActiveNotification
                        object:[UIApplication sharedApplication]];

    [defaultCenter addObserver:self
                      selector:@selector(sharedLibraryFound:)
                          name:VLCSharedLibraryParserDeterminedNetserviceAsVLCInstance
                        object:nil];
137

138
/*    if (SYSTEM_RUNS_IOS7_OR_LATER)
139
        _sectionHeaderTexts = @[@"Universal Plug'n'Play (UPNP)", @"Plex Media Server (via Bonjour)", @"File Transfer Protocol (FTP)", NSLocalizedString(@"SHARED_VLC_IOS_LIBRARY", nil), @"libDSM", NSLocalizedString(@"SAP_STREAMS", nil)];
140
    else*/
141
    _sectionHeaderTexts = @[@"Universal Plug'n'Play (UPnP)", @"Plex Media Server (via Bonjour)", @"File Transfer Protocol (FTP)", NSLocalizedString(@"SHARED_VLC_IOS_LIBRARY", nil), @"libDSM"];
142 143 144 145

    _backToMenuButton = [UIBarButtonItem themedRevealMenuButtonWithTarget:self andSelector:@selector(goBack:)];
    self.navigationItem.leftBarButtonItem = _backToMenuButton;

146
    self.tableView.rowHeight = [VLCLocalNetworkListCell heightOfCell];
147 148
    self.tableView.separatorColor = [UIColor VLCDarkBackgroundColor];
    self.view.backgroundColor = [UIColor VLCDarkBackgroundColor];
149

150
    self.title = NSLocalizedString(@"LOCAL_NETWORK", nil);
151

152
    _ftpServices = [[NSMutableArray alloc] init];
153
    [_ftpServices addObject:NSLocalizedString(@"CONNECT_TO_SERVER", nil)];
154

155
    _rawNetServices = [[NSMutableArray alloc] init];
156

157 158
    _ftpNetServiceBrowser = [[NSNetServiceBrowser alloc] init];
    _ftpNetServiceBrowser.delegate = self;
Pierre SAGASPE's avatar
Pierre SAGASPE committed
159

160 161 162 163 164
    _PlexServices = [[NSMutableArray alloc] init];
    _PlexServicesInfo = [[NSMutableArray alloc] init];
    _PlexNetServiceBrowser = [[NSNetServiceBrowser alloc] init];
    _PlexNetServiceBrowser.delegate = self;

165 166 167 168 169
    _httpServices = [[NSMutableArray alloc] init];
    _httpServicesInfo = [[NSMutableArray alloc] init];
    _httpNetServiceBrowser = [[NSNetServiceBrowser alloc] init];
    _httpNetServiceBrowser.delegate = self;

170
    _refreshControl = [[UIRefreshControl alloc] init];
171 172
    _refreshControl.backgroundColor = [UIColor VLCDarkBackgroundColor];
    _refreshControl.tintColor = [UIColor whiteColor];
173 174
    [_refreshControl addTarget:self action:@selector(handleRefresh) forControlEvents:UIControlEventValueChanged];
    [self.tableView addSubview:_refreshControl];
175

Carola's avatar
Carola committed
176 177 178 179 180
    if (SYSTEM_RUNS_IOS7_OR_LATER)
        _loginViewController = [[VLCNetworkLoginViewController alloc] initWithNibName:@"VLCFutureNetworkLoginViewController" bundle:nil];
    else
        _loginViewController = [[VLCNetworkLoginViewController alloc] initWithNibName:@"VLCNetworkLoginViewController" bundle:nil];

181
    _loginViewController.delegate = self;
182 183 184 185 186 187

    _reachability = [Reachability reachabilityForLocalWiFi];
    [_reachability startNotifier];

    [self netReachabilityChanged:nil];

188 189
    self.uploadController = [[VLCHTTPUploaderController alloc] init];
    _myHostName = [self.uploadController hostname];
190
    _httpParser = [[VLCSharedLibraryParser alloc] init];
191

192
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(netReachabilityChanged:) name:kReachabilityChangedNotification object:nil];
193 194 195 196 197
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
198
    [_activityIndicator stopAnimating];
199
    [_ftpNetServiceBrowser stop];
200
    [_PlexNetServiceBrowser stop];
201
    [_httpNetServiceBrowser stop];
202 203 204 205
}

- (void)viewWillAppear:(BOOL)animated
{
206
    [_ftpNetServiceBrowser searchForServicesOfType:@"_ftp._tcp." inDomain:@""];
207
    [_PlexNetServiceBrowser searchForServicesOfType:kPlexServiceType inDomain:@""];
208
    [_httpNetServiceBrowser searchForServicesOfType:@"_http._tcp." inDomain:@""];
209
    [_activityIndicator stopAnimating];
210
    [super viewWillAppear:animated];
211 212 213 214 215 216 217 218 219

    [self netReachabilityChanged:nil];
}

- (void)netReachabilityChanged:(NSNotification *)notification
{
    if (_reachability.currentReachabilityStatus == ReachableViaWiFi) {
        [self performSelectorInBackground:@selector(_startUPNPDiscovery) withObject:nil];
        [self performSelectorInBackground:@selector(_startSAPDiscovery) withObject:nil];
220
        [self performSelectorInBackground:@selector(_startDSMDiscovery) withObject:nil];
221 222 223
    } else {
        [self _stopUPNPDiscovery];
        [self _stopSAPDiscovery];
224
        [self _stopDSMDiscovery];
225
    }
226 227
}

228 229
- (void)_startUPNPDiscovery
{
230 231 232
    if (_reachability.currentReachabilityStatus != ReachableViaWiFi)
        return;

233
    UPnPManager *managerInstance = [UPnPManager GetInstance];
234

235 236
    _UPNPdevices = [[managerInstance DB] rootDevices];

237 238 239
    if (_UPNPdevices.count > 0)
        [self UPnPDBUpdated:nil];

240
    [[managerInstance DB] addObserver:self];
241 242

    //Optional; set User Agent
243
    [[managerInstance SSDP] setUserAgentProduct:[NSString stringWithFormat:@"VLCforiOS/%@", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]] andOS:[NSString stringWithFormat:@"iOS/%@", [[UIDevice currentDevice] systemVersion]]];
244 245

    //Search for UPnP Devices
246
    [[managerInstance SSDP] startSSDP];
247 248 249 250 251 252 253 254 255 256
    [[managerInstance SSDP] notifySSDPAlive];
    _searchTimer = [NSTimer timerWithTimeInterval:10.0 target:self selector:@selector(_performSSDPSearch) userInfo:nil repeats:YES];
    [_searchTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
    [[NSRunLoop mainRunLoop] addTimer:_searchTimer forMode:NSRunLoopCommonModes];
    _udnpDiscoveryRunning = YES;
}

- (void)_performSSDPSearch
{
    UPnPManager *managerInstance = [UPnPManager GetInstance];
257
    [[managerInstance SSDP] searchSSDP];
258
    [[managerInstance SSDP] searchForMediaServer];
259
    [[managerInstance SSDP] SSDPDBUpdate];
260 261 262 263 264 265
}

- (void)_stopUPNPDiscovery
{
    if (_udnpDiscoveryRunning) {
        UPnPManager *managerInstance = [UPnPManager GetInstance];
266 267 268 269
        [[managerInstance SSDP] notifySSDPByeBye];
        [_searchTimer invalidate];
        _searchTimer = nil;
        [[managerInstance DB] removeObserver:self];
270 271 272
        [[managerInstance SSDP] stopSSDP];
        _udnpDiscoveryRunning = NO;
    }
273 274 275 276
}

- (IBAction)goBack:(id)sender
{
277
    [self _stopUPNPDiscovery];
278
    [self _stopSAPDiscovery];
279
    [self _stopDSMDiscovery];
280

281 282 283
    [[(VLCAppDelegate*)[UIApplication sharedApplication].delegate revealController] toggleSidebar:![(VLCAppDelegate*)[UIApplication sharedApplication].delegate revealController].sidebarShowing duration:kGHRevealSidebarDefaultAnimationDuration];
}

284
- (BOOL)shouldAutorotate
285
{
286
    UIInterfaceOrientation toInterfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
287 288 289 290 291
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
        return NO;
    return YES;
}

292 293
#pragma mark - table view handling

294 295
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
296
    return _sectionHeaderTexts.count;
297 298 299 300
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
301 302
    if (section == 0)
        return _filteredUPNPDevices.count;
303
    else if (section == 1)
304
        return (_PlexServices.count + 1);
305
    else if (section == 2)
306 307
        return _ftpServices.count;
    else if (section == 3)
308 309
        return _httpServices.count;
    else if (section == 4)
310 311
        return _dsmDiscoverer.discoveredMedia.count;
    else if (section == 5)
312
        return _sapDiscoverer.discoveredMedia.count;
313 314

    return 0;
315 316
}

317
- (void)tableView:(UITableView *)tableView willDisplayCell:(VLCLocalNetworkListCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
318
{
319
    UIColor *color = (indexPath.row % 2 == 0)? [UIColor blackColor]: [UIColor VLCDarkBackgroundColor];
320
    cell.contentView.backgroundColor = cell.titleLabel.backgroundColor = cell.folderTitleLabel.backgroundColor = cell.subtitleLabel.backgroundColor = color;
321 322 323 324 325 326 327 328 329 330
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"LocalNetworkCell";

    VLCLocalNetworkListCell *cell = (VLCLocalNetworkListCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
        cell = [VLCLocalNetworkListCell cellWithReuseIdentifier:CellIdentifier];

331 332 333 334
    NSUInteger row = indexPath.row;
    NSUInteger section = indexPath.section;

    [cell setIsDirectory:YES];
335
    [cell setIcon:nil];
336 337

    if (section == 0) {
338 339 340 341 342 343
        UIImage *icon;
        if (_filteredUPNPDevices.count > row) {
            BasicUPnPDevice *device = _filteredUPNPDevices[row];
            [cell setTitle:[device friendlyName]];
            icon = [device smallIcon];
        }
Felix Paul Kühne's avatar
Felix Paul Kühne committed
344
        [cell setIcon:icon != nil ? icon : [UIImage imageNamed:@"serverIcon"]];
345
    } else if (section == 1) {
346 347 348 349 350 351 352
        NSInteger totalRow = [tableView numberOfRowsInSection:section];
        if (row == (totalRow - 1))
            [cell setTitle:NSLocalizedString(@"PLEX_CONNECT_TO_SERVER", nil)];
        else {
            [cell setTitle:[_PlexServices[row] name]];
            [cell setIcon:[UIImage imageNamed:@"PlexServerIcon"]];
        }
353
    } else if (section == 2) {
354 355
        if (row == 0)
            [cell setTitle:_ftpServices[row]];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
356
        else {
357
            [cell setTitle:[_ftpServices[row] name]];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
358 359
            [cell setIcon:[UIImage imageNamed:@"serverIcon"]];
        }
360 361 362 363
    } else if (section == 3) {
        [cell setTitle:[_httpServices[row] name]];
        [cell setIcon:[UIImage imageNamed:@"menuCone"]];
    } else if (section == 4)
364 365
        [cell setTitle:[[_dsmDiscoverer.discoveredMedia mediaAtIndex:row] metadataForKey: VLCMetaInformationTitle]];
    else if (section == 5)
366
        [cell setTitle:[[_sapDiscoverer.discoveredMedia mediaAtIndex:row] metadataForKey: VLCMetaInformationTitle]];
367 368 369 370 371 372

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
373 374
    [tableView deselectRowAtIndexPath:indexPath animated:YES];

375 376 377 378
    NSUInteger row = indexPath.row;
    NSUInteger section = indexPath.section;

    if (section == 0) {
379 380 381
        if (_filteredUPNPDevices.count < row || _filteredUPNPDevices.count == 0)
            return;

382
        [_activityIndicator startAnimating];
383
        BasicUPnPDevice *device = _filteredUPNPDevices[row];
384 385
        if ([[device urn] isEqualToString:@"urn:schemas-upnp-org:device:MediaServer:1"]) {
            MediaServer1Device *server = (MediaServer1Device*)device;
386
            VLCLocalServerFolderListViewController *targetViewController = [[VLCLocalServerFolderListViewController alloc] initWithUPNPDevice:server header:[device friendlyName] andRootID:@"0"];
387
            [self.navigationController pushViewController:targetViewController animated:YES];
388
        }
389
    } else if (section == 1) {
390 391 392 393 394 395 396 397
        NSInteger totalRow = [tableView numberOfRowsInSection:section];
        if (row == (totalRow - 1)) {
            VLCPlexConnectServerViewController *_connectPlexServer;
            if (SYSTEM_RUNS_IOS7_OR_LATER)
                _connectPlexServer = [[VLCPlexConnectServerViewController alloc] initWithNibName:@"VLCFuturePlexConnectServerViewController" bundle:nil];
            else
                _connectPlexServer = [[VLCPlexConnectServerViewController alloc] initWithNibName:@"VLCPlexConnectServerViewController" bundle:nil];

398
            UINavigationController *navCon = [[VLCNavigationController alloc] initWithRootViewController:_connectPlexServer];
399 400 401 402 403 404 405
            navCon.navigationBarHidden = NO;

            [self.navigationController pushViewController:_connectPlexServer animated:YES];
        } else {
            NSString *name = [_PlexServicesInfo[row] objectForKey:@"name"];
            NSString *hostName = [_PlexServicesInfo[row] objectForKey:@"hostName"];
            NSString *portNum = [_PlexServicesInfo[row] objectForKey:@"port"];
406
            VLCLocalPlexFolderListViewController *targetViewController = [[VLCLocalPlexFolderListViewController alloc] initWithPlexServer:name serverAddress:hostName portNumber:portNum atPath:@"" authentification:@""];
407 408
            [[self navigationController] pushViewController:targetViewController animated:YES];
        }
409
    } else if (section == 2) {
410
        UINavigationController *navCon = [[VLCNavigationController alloc] initWithRootViewController:_loginViewController];
411 412 413 414
        navCon.navigationBarHidden = NO;

        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
            navCon.modalPresentationStyle = UIModalPresentationFormSheet;
415
            [self presentViewController:navCon animated:YES completion:nil];
416

417 418
            if (_loginViewController.navigationItem.leftBarButtonItem == nil)
                _loginViewController.navigationItem.leftBarButtonItem = [UIBarButtonItem themedDarkToolbarButtonWithTitle:NSLocalizedString(@"BUTTON_DONE", nil) target:_loginViewController andSelector:@selector(dismissWithAnimation:)];
419
        } else
420
            [self.navigationController pushViewController:_loginViewController animated:YES];
421

Felix Paul Kühne's avatar
Felix Paul Kühne committed
422
        if (row != 0 && [_ftpServices[row] hostName].length > 0) // FTP Connect To Server Special Item and hostname is long enough
423
            _loginViewController.hostname = [_ftpServices[row] hostName];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
424
        else
425
            _loginViewController.hostname = @"";
426
    } else if (section == 3) {
427 428 429
        NSString *name = [_httpServicesInfo[row] objectForKey:@"name"];
        NSString *hostName = [_httpServicesInfo[row] objectForKey:@"hostName"];
        NSString *portNum = [_httpServicesInfo[row] objectForKey:@"port"];
430 431 432 433
        VLCSharedLibraryListViewController *targetViewController = [[VLCSharedLibraryListViewController alloc]
                                                                    initWithHttpServer:name
                                                                    serverAddress:hostName
                                                                    portNumber:portNum];
434
        [[self navigationController] pushViewController:targetViewController animated:YES];
435
    } else if (section == 4) {
436 437
        NSLog(@"DSM entry selected");
    } else if (section == 5) {
438
        VLCAppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
439
        [appDelegate openMovieFromURL:[[_sapDiscoverer.discoveredMedia mediaAtIndex:row] url]];
440
    }
441 442
}

Pierre SAGASPE's avatar
Pierre SAGASPE committed
443 444 445 446
#pragma mark - Refresh

-(void)handleRefresh
{
447 448 449 450
    if (_reachability.currentReachabilityStatus != ReachableViaWiFi) {
        [_refreshControl endRefreshing];
        return;
    }
Pierre SAGASPE's avatar
Pierre SAGASPE committed
451
    UPnPManager *managerInstance = [UPnPManager GetInstance];
452
    [[managerInstance DB] removeObserver:self];
Pierre SAGASPE's avatar
Pierre SAGASPE committed
453
    [[managerInstance SSDP] stopSSDP];
454
    [self _stopDSMDiscovery];
Pierre SAGASPE's avatar
Pierre SAGASPE committed
455

Pierre SAGASPE's avatar
Pierre SAGASPE committed
456
    //set the title while refreshing
457
    _refreshControl.attributedTitle = [[NSAttributedString alloc]initWithString:NSLocalizedString(@"LOCAL_SERVER_REFRESH",nil)];
Pierre SAGASPE's avatar
Pierre SAGASPE committed
458 459 460
    //set the date and time of refreshing
    NSDateFormatter *formattedDate = [[NSDateFormatter alloc]init];
    [formattedDate setDateFormat:@"MMM d, h:mm a"];
461
    NSString *lastupdated = [NSString stringWithFormat:NSLocalizedString(@"LOCAL_SERVER_LAST_UPDATE",nil),[formattedDate stringFromDate:[NSDate date]]];
462 463
    NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject:[UIColor whiteColor] forKey:NSForegroundColorAttributeName];
    _refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:lastupdated attributes:attrsDictionary];
Pierre SAGASPE's avatar
Pierre SAGASPE committed
464
    //end the refreshing
465
    [_refreshControl endRefreshing];
Pierre SAGASPE's avatar
Pierre SAGASPE committed
466 467 468 469

    [self.tableView reloadData];

    [self performSelectorInBackground:@selector(_startUPNPDiscovery) withObject:nil];
470
    [self performSelectorInBackground:@selector(_startSAPDiscovery) withObject:nil];
471
    [self performSelectorInBackground:@selector(_startDSMDiscovery) withObject:nil];
Pierre SAGASPE's avatar
Pierre SAGASPE committed
472 473
}

474 475
#pragma mark - login panel protocol

476
- (void)loginToURL:(NSURL *)url confirmedWithUsername:(NSString *)username andPassword:(NSString *)password
477
{
478 479 480 481 482 483 484
    if ([url.scheme isEqualToString:@"ftp"]) {
        if (url.host.length > 0) {
            VLCLocalServerFolderListViewController *targetViewController = [[VLCLocalServerFolderListViewController alloc] initWithFTPServer:url.host userName:username andPassword:password atPath:@"/"];
            [self.navigationController pushViewController:targetViewController animated:YES];
        }
    } else
        APLog(@"Unsupported URL Scheme requested %@", url.scheme);
485 486
}

487 488
#pragma mark - custom table view appearance

489 490
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
491 492 493
    return 21.f;
}

494 495
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
496
    NSObject *headerText = NSLocalizedString(_sectionHeaderTexts[section], nil);
497 498 499
    UIView *headerView = nil;
    if (headerText != [NSNull null]) {
        headerView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, [UIScreen mainScreen].bounds.size.height, 21.0f)];
500 501 502 503 504 505 506 507
        if (!SYSTEM_RUNS_IOS7_OR_LATER) {
            CAGradientLayer *gradient = [CAGradientLayer layer];
            gradient.frame = headerView.bounds;
            gradient.colors = @[
                          (id)[UIColor colorWithRed:(66.0f/255.0f) green:(66.0f/255.0f) blue:(66.0f/255.0f) alpha:1.0f].CGColor,
                          (id)[UIColor colorWithRed:(56.0f/255.0f) green:(56.0f/255.0f) blue:(56.0f/255.0f) alpha:1.0f].CGColor,
                          ];
            [headerView.layer insertSublayer:gradient atIndex:0];
508
        } else
509
            headerView.backgroundColor = [UIColor VLCDarkBackgroundColor];
510

511
        UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectInset(headerView.bounds, 12.0f, 0.f)];
512 513 514
        textLabel.text = (NSString *) headerText;
        textLabel.font = [UIFont fontWithName:@"Helvetica-Bold" size:([UIFont systemFontSize] * 0.8f)];
        textLabel.shadowOffset = CGSizeMake(0.0f, 1.0f);
515
        textLabel.shadowColor = [UIColor VLCDarkTextShadowColor];
516 517 518 519 520 521
        textLabel.textColor = [UIColor colorWithRed:(118.0f/255.0f) green:(118.0f/255.0f) blue:(118.0f/255.0f) alpha:1.0f];
        textLabel.backgroundColor = [UIColor clearColor];
        [headerView addSubview:textLabel];

        UIView *topLine = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, [UIScreen mainScreen].bounds.size.height, 1.0f)];
        topLine.backgroundColor = [UIColor colorWithRed:(95.0f/255.0f) green:(95.0f/255.0f) blue:(95.0f/255.0f) alpha:1.0f];
522
        topLine.autoresizingMask = UIViewAutoresizingFlexibleWidth;
523 524 525 526
        [headerView addSubview:topLine];

        UIView *bottomLine = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 21.0f, [UIScreen mainScreen].bounds.size.height, 1.0f)];
        bottomLine.backgroundColor = [UIColor colorWithRed:(16.0f/255.0f) green:(16.0f/255.0f) blue:(16.0f/255.0f) alpha:1.0f];
527
        bottomLine.autoresizingMask = UIViewAutoresizingFlexibleWidth;
528 529 530
        [headerView addSubview:bottomLine];
    }
    return headerView;
531 532
}

533 534 535
#pragma mark - bonjour discovery
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
{
536
    APLog(@"found bonjour service: %@ (%@)", aNetService.name, aNetService.type);
537
    [_rawNetServices addObject:aNetService];
538
    aNetService.delegate = self;
539
    [aNetService resolveWithTimeout:5.];
540 541 542 543
}

- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
{
544
    APLog(@"bonjour service disappeared: %@ (%i)", aNetService.name, moreComing);
545 546
    if ([_rawNetServices containsObject:aNetService])
        [_rawNetServices removeObject:aNetService];
547 548
    if ([aNetService.type isEqualToString:@"_ftp._tcp."])
        [_ftpServices removeObject:aNetService];
549 550 551 552
    if ([aNetService.type isEqualToString:kPlexServiceType]) {
        [_PlexServices removeObject:aNetService];
        [_PlexServicesInfo removeAllObjects];
    }
553 554 555 556
    if ([aNetService.type isEqualToString:@"_http._tcp."]) {
        [_httpServices removeObject:aNetService];
        [_httpServicesInfo removeAllObjects];
    }
557 558 559 560
    if (!moreComing)
        [self.tableView reloadData];
}

561 562 563 564 565
- (void)netServiceDidResolveAddress:(NSNetService *)aNetService
{
    if ([aNetService.type isEqualToString:@"_ftp._tcp."]) {
        if (![_ftpServices containsObject:aNetService])
            [_ftpServices addObject:aNetService];
566 567 568 569 570 571 572 573 574 575
    } else if ([aNetService.type isEqualToString:kPlexServiceType]) {
        if (![_PlexServices containsObject:aNetService]) {
            [_PlexServices addObject:aNetService];
            NSMutableDictionary *_dictService = [[NSMutableDictionary alloc] init];
            [_dictService setObject:[aNetService name] forKey:@"name"];
            [_dictService setObject:[aNetService hostName] forKey:@"hostName"];
            NSString *portStr = [[NSString alloc] initWithFormat:@":%ld", (long)[aNetService port]];
            [_dictService setObject:portStr forKey:@"port"];
            [_PlexServicesInfo addObject:_dictService];
        }
576 577
    }  else if ([aNetService.type isEqualToString:@"_http._tcp."]) {
        if ([[aNetService hostName] rangeOfString:_myHostName].location == NSNotFound) {
578
            [_httpParser checkNetserviceForVLCService:aNetService];
579
        }
580
    }
581
    [_rawNetServices removeObject:aNetService];
582 583 584 585 586 587
    [self.tableView reloadData];
}

- (void)netService:(NSNetService *)aNetService didNotResolve:(NSDictionary *)errorDict
{
    APLog(@"failed to resolve: %@", aNetService.name);
588
    [_rawNetServices removeObject:aNetService];
589 590
}

591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
#pragma mark - shared library stuff

- (void)sharedLibraryFound:(NSNotification *)aNotification
{
    NSNetService *aNetService = [aNotification.userInfo objectForKey:@"aNetService"];

    if (![_httpServices containsObject:aNetService]) {
        [_httpServices addObject:aNetService];
        NSMutableDictionary *_dictService = [[NSMutableDictionary alloc] init];
        [_dictService setObject:[aNetService name] forKey:@"name"];
        [_dictService setObject:[aNetService hostName] forKey:@"hostName"];
        NSString *portStr = [[NSString alloc] initWithFormat:@"%ld", (long)[aNetService port]];
        [_dictService setObject:portStr forKey:@"port"];
        [_httpServicesInfo addObject:_dictService];
    }
}

608
#pragma mark - UPNP details
609
//protocol UPnPDBObserver
610 611
- (void)UPnPDBWillUpdate:(UPnPDB*)sender
{
612 613
}

614 615
- (void)UPnPDBUpdated:(UPnPDB*)sender
{
616
    NSUInteger count = _UPNPdevices.count;
617 618 619
    BasicUPnPDevice *device;
    NSMutableArray *mutArray = [[NSMutableArray alloc] init];
    for (NSUInteger x = 0; x < count; x++) {
620
        device = _UPNPdevices[x];
621 622
        if ([[device urn] isEqualToString:@"urn:schemas-upnp-org:device:MediaServer:1"])
            [mutArray addObject:device];
623 624
        else
            APLog(@"found device '%@' with unsupported urn '%@'", [device friendlyName], [device urn]);
625
    }
626 627
    _filteredUPNPDevices = nil;
    _filteredUPNPDevices = [NSArray arrayWithArray:mutArray];
628

629 630 631 632 633 634 635
    [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
}

#pragma mark SAP discovery

- (void)_startSAPDiscovery
{
636
    return;
637

638 639 640
    if (_reachability.currentReachabilityStatus != ReachableViaWiFi)
        return;

641
    _sapDiscoverer = [[VLCMediaDiscoverer alloc] initWithName:@"sap"];
642
    [_sapDiscoverer startDiscoverer];
643 644 645 646 647
    _sapDiscoverer.discoveredMedia.delegate = self;
}

- (void)_stopSAPDiscovery
{
648
    return;
649

650
    [_sapDiscoverer stopDiscoverer];
651 652 653 654 655 656 657 658 659 660 661
    _sapDiscoverer = nil;
}

- (void)mediaList:(VLCMediaList *)aMediaList mediaAdded:(VLCMedia *)media atIndex:(NSInteger)index
{
    [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
}

- (void)mediaList:(VLCMediaList *)aMediaList mediaRemovedAtIndex:(NSInteger)index
{
    [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
662 663
}

664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
#pragma DSM discovery

- (void)_startDSMDiscovery
{
    if (_reachability.currentReachabilityStatus != ReachableViaWiFi)
        return;

    if (!_dsmDiscoverer)
        _dsmDiscoverer = [[VLCMediaDiscoverer alloc] initWithName:@"dsm"];
    [_dsmDiscoverer startDiscoverer];
    _dsmDiscoverer.discoveredMedia.delegate = self;
}

- (void)_stopDSMDiscovery
{
    [_dsmDiscoverer stopDiscoverer];
680
    _dsmDiscoverer = nil;
681 682
}

683
@end