VLCServerListTVViewController.m 13.4 KB
Newer Older
Felix Paul Kühne's avatar
Felix Paul Kühne committed
1
2
3
4
5
6
7
8
9
10
/*****************************************************************************
 * VLC for iOS
 *****************************************************************************
 * Copyright (c) 2015 VideoLAN. All rights reserved.
 * $Id$
 *
 * Authors: Tobias Conradi <videolan # tobias-conradi.de>
 *
 * Refer to the COPYING file of the official project for license.
 *****************************************************************************/
Tobias's avatar
Tobias committed
11

12
#import "VLCServerListTVViewController.h"
Tobias's avatar
Tobias committed
13
#import "VLCLocalNetworkServerTVCell.h"
14
#import "VLCServerBrowsingTVViewController.h"
15
16
17
18
#import "VLCNetworkServerLoginInformation.h"

#import "VLCNetworkServerBrowserPlex.h"
#import "VLCNetworkServerBrowserVLCMedia.h"
19
#import "VLCNetworkServerBrowserFTP.h"
20
#import <SSKeychain/SSKeychain.h>
Tobias's avatar
Tobias committed
21

22
23
24
25
26
27
28
29
30
31
#import "VLCLocalNetworkServiceBrowserManualConnect.h"
#import "VLCLocalNetworkServiceBrowserPlex.h"
#import "VLCLocalNetworkServiceBrowserFTP.h"
#import "VLCLocalNetworkServiceBrowserUPnP.h"
#ifndef NDEBUG
#import "VLCLocalNetworkServiceBrowserSAP.h"
#endif
#import "VLCLocalNetworkServiceBrowserDSM.h"
#import "VLCLocalNetworkServiceBrowserHTTP.h"

32
33
34
#import "VLCRemoteBrowsingTVCell.h"

@interface VLCServerListTVViewController ()
35
36
37
{
    UILabel *_nothingFoundLabel;
}
38
@property (nonatomic) NSArray <NSIndexPath *> *indexPaths;
Tobias's avatar
Tobias committed
39
40
@end

41
42
43
44
45
46
@implementation VLCServerListTVViewController

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    return [super initWithNibName:@"VLCRemoteBrowsingCollectionViewController" bundle:nil];
}
Tobias's avatar
Tobias committed
47
48
49

- (void)viewDidLoad {
    [super viewDidLoad];
50
51
    self.automaticallyAdjustsScrollViewInsets = NO;
    self.edgesForExtendedLayout = UIRectEdgeAll ^ UIRectEdgeTop;
52
53

    UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)self.collectionViewLayout;
54
55
56
    flowLayout.itemSize = CGSizeMake(250.0, 300.0);
    flowLayout.minimumInteritemSpacing = 48.0;
    flowLayout.minimumLineSpacing = 100.0;
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

    _nothingFoundLabel = [[UILabel alloc] init];
    _nothingFoundLabel.text = NSLocalizedString(@"NO_SERVER_FOUND", nil);
    _nothingFoundLabel.textAlignment = NSTextAlignmentCenter;
    _nothingFoundLabel.textColor = [UIColor VLCLightTextColor];
    _nothingFoundLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleTitle3];
    [_nothingFoundLabel sizeToFit];
    [_nothingFoundLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:_nothingFoundLabel];

    NSLayoutConstraint *yConstraint = [NSLayoutConstraint constraintWithItem:_nothingFoundLabel
                                                                   attribute:NSLayoutAttributeCenterY
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self.view
                                                                   attribute:NSLayoutAttributeCenterY
                                                                  multiplier:1.0
                                                                    constant:0.0];
    [self.view addConstraint:yConstraint];
    NSLayoutConstraint *xConstraint = [NSLayoutConstraint constraintWithItem:_nothingFoundLabel
                                                                   attribute:NSLayoutAttributeCenterX
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self.view
                                                                   attribute:NSLayoutAttributeCenterX
                                                                  multiplier:1.0
                                                                    constant:0.0];
    [self.view addConstraint:xConstraint];
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

    NSArray *classes = @[
                         //                         [VLCLocalNetworkServiceBrowserManualConnect class],
                         [VLCLocalNetworkServiceBrowserHTTP class],
                         [VLCLocalNetworkServiceBrowserUPnP class],
                         [VLCLocalNetworkServiceBrowserDSM class],
                         [VLCLocalNetworkServiceBrowserPlex class],
                         [VLCLocalNetworkServiceBrowserFTP class],
#ifndef NDEBUG
                         [VLCLocalNetworkServiceBrowserSAP class],
#endif
                         ];
    self.discoveryController = [[VLCLocalServerDiscoveryController alloc] initWithServiceBrowserClasses:classes];
    self.discoveryController.delegate = self;
}

- (NSString *)title {
    return NSLocalizedString(@"LOCAL_NETWORK", nil);
101
}
Felix Paul Kühne's avatar
Felix Paul Kühne committed
102
103
104

- (void)viewDidAppear:(BOOL)animated
{
105
106
107
    [super viewDidAppear:animated];
    [self.discoveryController startDiscovery];
}
Felix Paul Kühne's avatar
Felix Paul Kühne committed
108
109
110

- (void)viewDidDisappear:(BOOL)animated
{
111
112
    [super viewDidDisappear:animated];
    [self.discoveryController stopDiscovery];
Tobias's avatar
Tobias committed
113
114
}

115
#pragma mark - Collection view data source
Tobias's avatar
Tobias committed
116

117
118
119
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return self.indexPaths.count;
120
121
}

122
123
124
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
    VLCRemoteBrowsingTVCell *browsingCell = (VLCRemoteBrowsingTVCell *) [collectionView dequeueReusableCellWithReuseIdentifier:VLCRemoteBrowsingTVCellIdentifier forIndexPath:indexPath];
Tobias's avatar
Tobias committed
125

126
127
    NSIndexPath *discoveryIndexPath = self.indexPaths[indexPath.row];
    id<VLCLocalNetworkService> service = [self.discoveryController networkServiceForIndexPath:discoveryIndexPath];
Tobias's avatar
Tobias committed
128

129
130
    browsingCell.isDirectory = YES;
    browsingCell.title = service.title;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
131
    browsingCell.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption2];
132
133
134
    browsingCell.subtitle = [self.discoveryController titleForSection:discoveryIndexPath.section];
    browsingCell.subtitleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
    browsingCell.thumbnailImage = service.icon ? service.icon : [UIImage imageNamed:@"serverIcon"];
135

136
137
    return browsingCell;
}
138

139
140
141
142
143
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSIndexPath *discoveryIndexPath = self.indexPaths[indexPath.row];
    id<VLCLocalNetworkService> service = [self.discoveryController networkServiceForIndexPath:discoveryIndexPath];
    [self didSelectService:service];
144
145
146
}


147
148
149
150
#pragma mark - Service specific stuff

- (void)didSelectService:(id<VLCLocalNetworkService>)service
{
151
152
153
    if ([service respondsToSelector:@selector(serverBrowser)]) {
        id <VLCNetworkServerBrowser> browser = [service serverBrowser];
        if (browser) {
154
            VLCServerBrowsingTVViewController *browsingViewController = [[VLCServerBrowsingTVViewController alloc] initWithServerBrowser:browser];
155
156
157
            [self presentViewController:[[UINavigationController alloc] initWithRootViewController:browsingViewController]
                               animated:YES
                             completion:nil];
158
159
160
161
162
            return;
        }
    }

    if ([service respondsToSelector:@selector(loginInformation)]) {
163
164
165
166
        VLCNetworkServerLoginInformation *login = service.loginInformation;
        if (!login) return;
        [self showLoginAlertWithLogin:login];

167
168
        return;
    }
169

170
    if ([service respondsToSelector:@selector(directPlaybackURL)]) {
171
172
173
174
175
176
177
178
179

        NSURL *url = service.directPlaybackURL;
        if (!url) return;

        VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
        [vpc playURL:url subtitlesFilePath:nil];
        [self presentViewController:[VLCFullscreenMovieTVViewController fullscreenMovieTVViewController]
                           animated:YES
                         completion:nil];
180
181
        return;
    }
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
}

- (void)showLoginAlertWithLogin:(nonnull VLCNetworkServerLoginInformation *)login
{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"CONNECT_TO_SERVER", nil)
                                                                             message:login.address preferredStyle:UIAlertControllerStyleAlert];


    NSURLComponents *components = [[NSURLComponents alloc] init];
    components.scheme = login.protocolIdentifier;
    components.host = login.address;
    components.port = login.port;
    NSString *serviceIdentifier = components.URL.absoluteString;
    NSString *accountName = [SSKeychain accountsForService:serviceIdentifier].firstObject[kSSKeychainAccountKey];
    NSString *password = [SSKeychain passwordForService:serviceIdentifier account:accountName];


    __block UITextField *usernameField = nil;
    __block UITextField *passwordField = nil;
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = NSLocalizedString(@"USER_LABEL", nil);
        textField.text = accountName;
        usernameField = textField;
    }];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.secureTextEntry = YES;
        textField.placeholder = NSLocalizedString(@"PASSWORD_LABEL", nil);
        textField.text = password;
        passwordField = textField;
    }];
    [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"LOGIN", nil)
                                                        style:UIAlertActionStyleDefault
                                                      handler:^(UIAlertAction * _Nonnull action) {
                                                          login.username = usernameField.text;
                                                          login.password = passwordField.text;
                                                          [self showBrowserWithLogin:login];
                                                      }]];

    [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_SAVE", nil)
                                                        style:UIAlertActionStyleDefault
                                                      handler:^(UIAlertAction * _Nonnull action) {
                                                          NSString *accountName = usernameField.text;
                                                          NSString *password = passwordField.text;
                                                          [SSKeychain setPassword:password forService:serviceIdentifier account:accountName];
                                                          login.username = accountName;
                                                          login.password = password;
                                                          [self showBrowserWithLogin:login];
                                                      }]];
    if (accountName.length && password.length) {
        [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_DELETE", nil)
                                                            style:UIAlertActionStyleDestructive
                                                          handler:^(UIAlertAction * _Nonnull action) {
                                                              [SSKeychain deletePasswordForService:serviceIdentifier account:accountName];
                                                          }]];
    }

    [alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_CANCEL", nil)
                                                        style:UIAlertActionStyleCancel
                                                      handler:nil]];
241

242
243
244
245
246
247
248
249
    [self presentViewController:alertController animated:YES completion:nil];
}

- (void)showBrowserWithLogin:(nonnull VLCNetworkServerLoginInformation *)login
{
    id<VLCNetworkServerBrowser> serverBrowser = nil;
    NSString *identifier = login.protocolIdentifier;

250
251
252
    if ([identifier isEqualToString:VLCNetworkServerProtocolIdentifierFTP]) {
        serverBrowser = [[VLCNetworkServerBrowserFTP alloc] initWithLogin:login];
    } else if ([identifier isEqualToString:VLCNetworkServerProtocolIdentifierPlex]) {
253
254
255
256
257
258
        serverBrowser = [[VLCNetworkServerBrowserPlex alloc] initWithLogin:login];
    } else if ([identifier isEqualToString:VLCNetworkServerProtocolIdentifierSMB]) {
        serverBrowser = [VLCNetworkServerBrowserVLCMedia SMBNetworkServerBrowserWithLogin:login];
    }

    if (serverBrowser) {
259
        VLCServerBrowsingTVViewController *targetViewController = [[VLCServerBrowsingTVViewController alloc] initWithServerBrowser:serverBrowser];
260
261
262
263
        [self presentViewController:[[UINavigationController alloc] initWithRootViewController:targetViewController]
                           animated:YES
                         completion:nil];
    }
Tobias's avatar
Tobias committed
264
265
266
}

#pragma mark - VLCLocalServerDiscoveryController
267
268
- (void)discoveryFoundSomethingNew
{
269
270
271
272
273
274
275
276
277
278
279
280
281
    NSMutableArray<NSIndexPath *> *indexPaths = [NSMutableArray array];
    VLCLocalServerDiscoveryController *discoveryController = self.discoveryController;
    NSUInteger sectionCount = [discoveryController numberOfSections];
    for (NSUInteger section = 0; section < sectionCount; ++section) {
        NSUInteger itemsCount = [discoveryController numberOfItemsInSection:section];
        for (NSUInteger index = 0; index < itemsCount; ++index) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:section];
            [indexPaths addObject:indexPath];
        }
    }
    self.indexPaths = [indexPaths copy];

    [self.collectionView reloadData];
282
283

    _nothingFoundLabel.hidden = self.discoveryController.foundAnythingAtAll;
Tobias's avatar
Tobias committed
284
285
286
}

@end